1 /*
2 * Copyright (c) 1999, 2025, 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 */
25
26 package com.sun.tools.javac.parser;
27
28 import java.util.*;
29 import java.util.function.Function;
30 import java.util.function.Predicate;
31 import java.util.stream.Collectors;
32
33 import javax.lang.model.SourceVersion;
34
35 import com.sun.source.tree.CaseTree;
36 import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
37 import com.sun.source.tree.ModuleTree.ModuleKind;
38
39 import com.sun.tools.javac.code.*;
40 import com.sun.tools.javac.code.Source.Feature;
41 import com.sun.tools.javac.file.PathFileObject;
42 import com.sun.tools.javac.parser.Tokens.*;
43 import com.sun.tools.javac.resources.CompilerProperties.Errors;
44 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
45 import com.sun.tools.javac.resources.CompilerProperties.LintWarnings;
46 import com.sun.tools.javac.resources.CompilerProperties.Warnings;
47 import com.sun.tools.javac.tree.*;
48 import com.sun.tools.javac.tree.JCTree.*;
49 import com.sun.tools.javac.util.*;
50 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag;
51 import com.sun.tools.javac.util.JCDiagnostic.Error;
52 import com.sun.tools.javac.util.JCDiagnostic.Fragment;
53 import com.sun.tools.javac.util.List;
54
55 import static com.sun.tools.javac.parser.Tokens.TokenKind.*;
56 import static com.sun.tools.javac.parser.Tokens.TokenKind.ASSERT;
57 import static com.sun.tools.javac.parser.Tokens.TokenKind.CASE;
58 import static com.sun.tools.javac.parser.Tokens.TokenKind.CATCH;
59 import static com.sun.tools.javac.parser.Tokens.TokenKind.EQ;
60 import static com.sun.tools.javac.parser.Tokens.TokenKind.GT;
61 import static com.sun.tools.javac.parser.Tokens.TokenKind.IMPORT;
62 import static com.sun.tools.javac.parser.Tokens.TokenKind.LT;
63 import com.sun.tools.javac.parser.VirtualParser.VirtualScanner;
64 import static com.sun.tools.javac.tree.JCTree.Tag.*;
65 import static com.sun.tools.javac.resources.CompilerProperties.Fragments.ImplicitAndExplicitNotAllowed;
66 import static com.sun.tools.javac.resources.CompilerProperties.Fragments.VarAndExplicitNotAllowed;
67 import static com.sun.tools.javac.resources.CompilerProperties.Fragments.VarAndImplicitNotAllowed;
68 import com.sun.tools.javac.util.JCDiagnostic.SimpleDiagnosticPosition;
69
70 /**
71 * The parser maps a token sequence into an abstract syntax tree.
72 * The parser is a hand-written recursive-descent parser that
73 * implements the grammar described in the Java Language Specification.
74 * For efficiency reasons, an operator precedence scheme is used
75 * for parsing binary operation expressions.
76 *
77 * <p><b>This is NOT part of any supported API.
78 * If you write code that depends on this, you do so at your own risk.
79 * This code and its internal interfaces are subject to change or
80 * deletion without notice.</b>
81 */
82 public class JavacParser implements Parser {
83
84 /** The number of precedence levels of infix operators.
85 */
86 private static final int infixPrecedenceLevels = 10;
87
88 /** Is the parser instantiated to parse a module-info file ?
89 */
90 private final boolean parseModuleInfo;
91
92 /** The scanner used for lexical analysis.
93 */
94 protected Lexer S;
95
96 /** The factory to be used for abstract syntax tree construction.
97 */
98 protected TreeMaker F;
99
100 /** The log to be used for error diagnostics.
101 */
102 private Log log;
103
104 /** The Source language setting. */
105 private Source source;
106
107 /** The Preview language setting. */
108 private Preview preview;
109
110 /** The name table. */
111 private Names names;
112
113 /** End position mappings container */
114 protected final AbstractEndPosTable endPosTable;
115
116 /** A map associating "other nearby documentation comments"
117 * with the preferred documentation comment for a declaration. */
118 protected Map<Comment, List<Comment>> danglingComments = new HashMap<>();
119
120 // Because of javac's limited lookahead, some contexts are ambiguous in
121 // the presence of type annotations even though they are not ambiguous
122 // in the absence of type annotations. Consider this code:
123 // void m(String [] m) { }
124 // void m(String ... m) { }
125 // After parsing "String", javac calls bracketsOpt which immediately
126 // returns if the next character is not '['. Similarly, javac can see
127 // if the next token is ... and in that case parse an ellipsis. But in
128 // the presence of type annotations:
129 // void m(String @A [] m) { }
130 // void m(String @A ... m) { }
131 // no finite lookahead is enough to determine whether to read array
132 // levels or an ellipsis. Furthermore, if you call bracketsOpt, then
133 // bracketsOpt first reads all the leading annotations and only then
134 // discovers that it needs to fail. bracketsOpt needs a way to push
135 // back the extra annotations that it read. (But, bracketsOpt should
136 // not *always* be allowed to push back extra annotations that it finds
137 // -- in most contexts, any such extra annotation is an error.
138 //
139 // The following two variables permit type annotations that have
140 // already been read to be stored for later use. Alternate
141 // implementations are possible but would cause much larger changes to
142 // the parser.
143
144 /** Type annotations that have already been read but have not yet been used. **/
145 private List<JCAnnotation> typeAnnotationsPushedBack = List.nil();
146
147 /**
148 * If the parser notices extra annotations, then it either immediately
149 * issues an error (if this variable is false) or places the extra
150 * annotations in variable typeAnnotationsPushedBack (if this variable
151 * is true).
152 */
153 private boolean permitTypeAnnotationsPushBack = false;
154 private JCDiagnostic.Error unexpectedTopLevelDefinitionStartError;
155
156 interface ErrorRecoveryAction {
157 JCTree doRecover(JavacParser parser);
158 }
159
160 enum BasicErrorRecoveryAction implements ErrorRecoveryAction {
161 BLOCK_STMT {public JCTree doRecover(JavacParser parser) { return parser.parseStatementAsBlock(); }},
162 CATCH_CLAUSE {public JCTree doRecover(JavacParser parser) { return parser.catchClause(); }}
163 }
164
165 /** Construct a parser from a given scanner, tree factory and log.
166 */
167 protected JavacParser(ParserFactory fac,
168 Lexer S,
169 boolean keepDocComments,
170 boolean keepLineMap,
171 boolean keepEndPositions) {
172 this(fac, S, keepDocComments, keepLineMap, keepEndPositions, false);
173
174 }
175 /** Construct a parser from a given scanner, tree factory and log.
176 */
177 @SuppressWarnings("this-escape")
178 protected JavacParser(ParserFactory fac,
179 Lexer S,
180 boolean keepDocComments,
181 boolean keepLineMap,
182 boolean keepEndPositions,
183 boolean parseModuleInfo) {
184 this.S = S;
185 nextToken(); // prime the pump
186 this.F = fac.F;
187 this.log = fac.log;
188 this.names = fac.names;
189 this.source = fac.source;
190 this.preview = fac.preview;
191 this.allowStringFolding = fac.options.getBoolean("allowStringFolding", true);
192 this.keepDocComments = keepDocComments;
193 this.parseModuleInfo = parseModuleInfo;
194 this.docComments = newDocCommentTable(keepDocComments, fac);
195 this.keepLineMap = keepLineMap;
196 this.errorTree = F.Erroneous();
197 this.endPosTable = newEndPosTable(keepEndPositions);
198 this.allowYieldStatement = Feature.SWITCH_EXPRESSION.allowedInSource(source);
199 this.allowRecords = Feature.RECORDS.allowedInSource(source);
200 this.allowSealedTypes = Feature.SEALED_CLASSES.allowedInSource(source);
201 updateUnexpectedTopLevelDefinitionStartError(false);
202 }
203
204 /** Construct a parser from an existing parser, with minimal overhead.
205 */
206 @SuppressWarnings("this-escape")
207 protected JavacParser(JavacParser parser,
208 Lexer S) {
209 this.S = S;
210 this.token = parser.token;
211 this.F = parser.F;
212 this.log = parser.log;
213 this.names = parser.names;
214 this.source = parser.source;
215 this.preview = parser.preview;
216 this.allowStringFolding = parser.allowStringFolding;
217 this.keepDocComments = parser.keepDocComments;
218 this.parseModuleInfo = false;
219 this.docComments = parser.docComments;
220 this.errorTree = F.Erroneous();
221 this.endPosTable = newEndPosTable(false);
222 this.allowYieldStatement = Feature.SWITCH_EXPRESSION.allowedInSource(source);
223 this.allowRecords = Feature.RECORDS.allowedInSource(source);
224 this.allowSealedTypes = Feature.SEALED_CLASSES.allowedInSource(source);
225 updateUnexpectedTopLevelDefinitionStartError(false);
226 }
227
228 protected AbstractEndPosTable newEndPosTable(boolean keepEndPositions) {
229 return keepEndPositions
230 ? new SimpleEndPosTable()
231 : new MinimalEndPosTable();
232 }
233
234 protected DocCommentTable newDocCommentTable(boolean keepDocComments, ParserFactory fac) {
235 return keepDocComments ? new LazyDocCommentTable(fac) : null;
236 }
237
238 /** Switch: should we fold strings?
239 */
240 boolean allowStringFolding;
241
242 /** Switch: should we keep docComments?
243 */
244 boolean keepDocComments;
245
246 /** Switch: should we keep line table?
247 */
248 boolean keepLineMap;
249
250 /** Switch: is "this" allowed as an identifier?
251 * This is needed to parse receiver types.
252 */
253 boolean allowThisIdent;
254
255 /** Switch: is yield statement allowed in this source level?
256 */
257 boolean allowYieldStatement;
258
259 /** Switch: are records allowed in this source level?
260 */
261 boolean allowRecords;
262
263 /** Switch: are sealed types allowed in this source level?
264 */
265 boolean allowSealedTypes;
266
267 /** The type of the method receiver, as specified by a first "this" parameter.
268 */
269 JCVariableDecl receiverParam;
270
271 /** When terms are parsed, the mode determines which is expected:
272 * mode = EXPR : an expression
273 * mode = TYPE : a type
274 * mode = NOPARAMS : no parameters allowed for type
275 * mode = TYPEARG : type argument
276 * mode |= NOLAMBDA : lambdas are not allowed
277 */
278 protected static final int EXPR = 1 << 0;
279 protected static final int TYPE = 1 << 1;
280 protected static final int NOPARAMS = 1 << 2;
281 protected static final int TYPEARG = 1 << 3;
282 protected static final int DIAMOND = 1 << 4;
283 protected static final int NOLAMBDA = 1 << 5;
284
285 protected void setMode(int mode) {
286 this.mode = mode;
287 }
288
289 protected void setLastMode(int mode) {
290 lastmode = mode;
291 }
292
293 protected boolean isMode(int mode) {
294 return (this.mode & mode) != 0;
295 }
296
297 protected boolean wasTypeMode() {
298 return (lastmode & TYPE) != 0;
299 }
300
301 protected void selectExprMode() {
302 setMode((mode & NOLAMBDA) | EXPR);
303 }
304
305 protected void selectTypeMode() {
306 setMode((mode & NOLAMBDA) | TYPE);
307 }
308
309 /** The current mode.
310 */
311 protected int mode = 0;
312
313 /** The mode of the term that was parsed last.
314 */
315 protected int lastmode = 0;
316
317 /* ---------- token management -------------- */
318
319 protected Token token;
320
321 public Token token() {
322 return token;
323 }
324
325 public void nextToken() {
326 S.nextToken();
327 token = S.token();
328 }
329
330 protected boolean peekToken(Predicate<TokenKind> tk) {
331 return peekToken(0, tk);
332 }
333
334 protected boolean peekToken(int lookahead, Predicate<TokenKind> tk) {
335 return tk.test(S.token(lookahead + 1).kind);
336 }
337
338 protected boolean peekToken(Predicate<TokenKind> tk1, Predicate<TokenKind> tk2) {
339 return peekToken(0, tk1, tk2);
340 }
341
342 protected boolean peekToken(int lookahead, Predicate<TokenKind> tk1, Predicate<TokenKind> tk2) {
343 return tk1.test(S.token(lookahead + 1).kind) &&
344 tk2.test(S.token(lookahead + 2).kind);
345 }
346
347 protected boolean peekToken(Predicate<TokenKind> tk1, Predicate<TokenKind> tk2, Predicate<TokenKind> tk3) {
348 return peekToken(0, tk1, tk2, tk3);
349 }
350
351 protected boolean peekToken(int lookahead, Predicate<TokenKind> tk1, Predicate<TokenKind> tk2, Predicate<TokenKind> tk3) {
352 return tk1.test(S.token(lookahead + 1).kind) &&
353 tk2.test(S.token(lookahead + 2).kind) &&
354 tk3.test(S.token(lookahead + 3).kind);
355 }
356
357 @SuppressWarnings("unchecked")
358 protected boolean peekToken(Predicate<TokenKind>... kinds) {
359 return peekToken(0, kinds);
360 }
361
362 @SuppressWarnings("unchecked")
363 protected boolean peekToken(int lookahead, Predicate<TokenKind>... kinds) {
364 for (Predicate<TokenKind> kind : kinds) {
365 if (!kind.test(S.token(++lookahead).kind)) {
366 return false;
367 }
368 }
369 return true;
370 }
371
372 /* ---------- error recovery -------------- */
373
374 private JCErroneous errorTree;
375
376 /** Skip forward until a suitable stop token is found.
377 */
378 protected void skip(boolean stopAtImport, boolean stopAtMemberDecl, boolean stopAtIdentifier, boolean stopAtStatement) {
379 while (true) {
380 switch (token.kind) {
381 case SEMI:
382 nextToken();
383 return;
384 case PUBLIC:
385 case FINAL:
386 case ABSTRACT:
387 case MONKEYS_AT:
388 case EOF:
389 case CLASS:
390 case INTERFACE:
391 case ENUM:
392 return;
393 case IMPORT:
394 if (stopAtImport)
395 return;
396 break;
397 case LBRACE:
398 case RBRACE:
399 case PRIVATE:
400 case PROTECTED:
401 case STATIC:
402 case TRANSIENT:
403 case NATIVE:
404 case VOLATILE:
405 case SYNCHRONIZED:
406 case STRICTFP:
407 case LT:
408 case BYTE:
409 case SHORT:
410 case CHAR:
411 case INT:
412 case LONG:
413 case FLOAT:
414 case DOUBLE:
415 case BOOLEAN:
416 case VOID:
417 if (stopAtMemberDecl)
418 return;
419 break;
420 case UNDERSCORE:
421 case IDENTIFIER:
422 if (stopAtIdentifier)
423 return;
424 break;
425 case CASE:
426 case DEFAULT:
427 case IF:
428 case FOR:
429 case WHILE:
430 case DO:
431 case TRY:
432 case SWITCH:
433 case RETURN:
434 case THROW:
435 case BREAK:
436 case CONTINUE:
437 case ELSE:
438 case FINALLY:
439 case CATCH:
440 case THIS:
441 case SUPER:
442 case NEW:
443 if (stopAtStatement)
444 return;
445 break;
446 case ASSERT:
447 if (stopAtStatement)
448 return;
449 break;
450 }
451 nextToken();
452 }
453 }
454
455 protected JCErroneous syntaxError(int pos, Error errorKey) {
456 return syntaxError(pos, List.nil(), errorKey);
457 }
458
459 protected JCErroneous syntaxError(int pos, List<? extends JCTree> errs, Error errorKey) {
460 return syntaxError(pos, errs, errorKey, false);
461 }
462
463 private JCErroneous syntaxError(int pos, List<? extends JCTree> errs, Error errorKey, boolean noEofError) {
464 setErrorEndPos(pos);
465 JCErroneous err = F.at(pos).Erroneous(errs);
466 reportSyntaxError(err, errorKey, noEofError);
467 if (errs != null) {
468 JCTree last = errs.last();
469 if (last != null)
470 storeEnd(last, pos);
471 }
472 return toP(err);
473 }
474
475 private static final int RECOVERY_THRESHOLD = 50;
476 private int errorPos = Position.NOPOS;
477 private int count = 0;
478
479 /**
480 * Report a syntax using the given the position parameter and arguments,
481 * unless one was already reported at the same position.
482 */
483 protected void reportSyntaxError(int pos, Error errorKey) {
484 JCDiagnostic.DiagnosticPosition diag = new JCDiagnostic.SimpleDiagnosticPosition(pos);
485 reportSyntaxError(diag, errorKey);
486 }
487
488 /**
489 * Report a syntax error using the given DiagnosticPosition object and
490 * arguments, unless one was already reported at the same position.
491 */
492 protected void reportSyntaxError(JCDiagnostic.DiagnosticPosition diagPos, Error errorKey) {
493 reportSyntaxError(diagPos, errorKey, false);
494 }
495
496 private void reportSyntaxError(JCDiagnostic.DiagnosticPosition diagPos, Error errorKey, boolean noEofError) {
497 int pos = diagPos.getPreferredPosition();
498 if (pos > S.errPos() || pos == Position.NOPOS) {
499 if (token.kind == EOF && !noEofError) {
500 log.error(DiagnosticFlag.SYNTAX, diagPos, Errors.PrematureEof);
501 } else {
502 log.error(DiagnosticFlag.SYNTAX, diagPos, errorKey);
503 }
504 }
505 S.errPos(pos);
506 if (token.pos == errorPos && token.kind != EOF) {
507 //check for a possible infinite loop in parsing:
508 Assert.check(count++ < RECOVERY_THRESHOLD);
509 } else {
510 count = 0;
511 errorPos = token.pos;
512 }
513 }
514
515 /** If next input token matches given token, skip it, otherwise report
516 * an error.
517 */
518 public void accept(TokenKind tk) {
519 accept(tk, Errors::Expected);
520 }
521
522 /** If next input token matches given token, skip it, otherwise report
523 * an error.
524 */
525 public void accept(TokenKind tk, Function<TokenKind, Error> errorProvider) {
526 if (token.kind == tk) {
527 nextToken();
528 } else {
529 setErrorEndPos(token.pos);
530 reportSyntaxError(S.prevToken().endPos, errorProvider.apply(tk));
531 }
532 }
533
534 /** Report an illegal start of expression/type error at given position.
535 */
536 JCExpression illegal(int pos) {
537 setErrorEndPos(pos);
538 if (isMode(EXPR))
539 return syntaxError(pos, Errors.IllegalStartOfExpr);
540 else
541 return syntaxError(pos, Errors.IllegalStartOfType);
542
543 }
544
545 /** Report an illegal start of expression/type error at current position.
546 */
547 JCExpression illegal() {
548 return illegal(token.pos);
549 }
550
551 /** Diagnose a modifier flag from the set, if any. */
552 protected void checkNoMods(long mods) {
553 checkNoMods(token.pos, mods);
554 }
555
556 protected void checkNoMods(int pos, long mods) {
557 if (mods != 0) {
558 long lowestMod = mods & -mods;
559 log.error(DiagnosticFlag.SYNTAX, pos, Errors.ModNotAllowedHere(Flags.asFlagSet(lowestMod)));
560 }
561 }
562
563 /* ---------- doc comments --------- */
564
565 /** A table to store all documentation comments
566 * indexed by the tree nodes they refer to.
567 * defined only if option flag keepDocComment is set.
568 */
569 private final DocCommentTable docComments;
570
571 /** Record nearby documentation comments against the
572 * primary documentation comment for a declaration.
573 *
574 * Dangling documentation comments are handled as follows.
575 * 1. {@code Scanner} adds all doc comments to a queue of
576 * recent doc comments. The queue is flushed whenever
577 * it is known that the recent doc comments should be
578 * ignored and should not cause any warnings.
579 * 2. The primary documentation comment is the one obtained
580 * from the first token of any declaration.
581 * (using {@code token.getDocComment()}.
582 * 3. At the end of the "signature" of the declaration
583 * (that is, before any initialization or body for the
584 * declaration) any other "recent" comments are saved
585 * in a map using the primary comment as a key,
586 * using this method, {@code saveDanglingComments}.
587 * 4. When the tree node for the declaration is finally
588 * available, and the primary comment, if any,
589 * is "attached", (in {@link #attach}) any related
590 * dangling comments are reported to the log as warnings.
591 * 5. (Later) Warnings may be generated for the dangling
592 * comments, subject to the {@code -Xlint} and
593 * {@code @SuppressWarnings}.
594 *
595 * @param dc the primary documentation comment
596 */
597 private void saveDanglingDocComments(Comment dc) {
598 var recentComments = S.getDocComments();
599
600 switch (recentComments.size()) {
601 case 0:
602 // no recent comments
603 return;
604
605 case 1:
606 if (recentComments.peek() == dc) {
607 // no other recent comments
608 recentComments.remove();
609 return;
610 }
611 }
612
613 var lb = new ListBuffer<Comment>();
614 while (!recentComments.isEmpty()) {
615 var c = recentComments.remove();
616 if (c != dc) {
617 lb.add(c);
618 }
619 }
620 danglingComments.put(dc, lb.toList());
621 }
622
623 /** Make an entry into docComments hashtable,
624 * provided flag keepDocComments is set and given doc comment is non-null.
625 * If there are any related "dangling comments", register
626 * diagnostics to be handled later, when @SuppressWarnings
627 * can be taken into account.
628 *
629 * @param tree The tree to be used as index in the hashtable
630 * @param dc The doc comment to associate with the tree, or null.
631 * @return {@code tree}
632 */
633 protected <T extends JCTree> T attach(T tree, Comment dc) {
634 if (keepDocComments && dc != null) {
635 docComments.putComment(tree, dc);
636 }
637 reportDanglingComments(tree, dc);
638 return tree;
639 }
640
641 /** Reports all dangling comments associated with the
642 * primary comment for a declaration against the position
643 * of the tree node for a declaration.
644 *
645 * @param tree the tree node for the declaration
646 * @param dc the primary comment for the declaration
647 */
648 void reportDanglingComments(JCTree tree, Comment dc) {
649 var list = danglingComments.remove(dc);
650 if (list != null) {
651 list.forEach(c -> reportDanglingDocComment(tree, c));
652 }
653 }
654
655 /**
656 * Reports an individual dangling comment as a warning to the log.
657 * The comment may or not may generate an actual diagnostic, depending on
658 * the settings for {@code -Xlint} and/or {@code @SuppressWarnings}.
659 *
660 * @param c the comment
661 */
662 void reportDanglingDocComment(JCTree tree, Comment c) {
663 var pos = c.getPos();
664 if (pos != null && !shebang(c, pos)) {
665 pos = pos.withLintPosition(tree.getStartPosition());
666 S.lintWarning(pos, LintWarnings.DanglingDocComment);
667 }
668 }
669
670 /** Returns true for a comment that acts similarly to shebang in UNIX */
671 private boolean shebang(Comment c, JCDiagnostic.DiagnosticPosition pos) {
672 var src = log.currentSource();
673 return c.getStyle() == Comment.CommentStyle.JAVADOC_LINE &&
674 c.getPos().getStartPosition() == 0 &&
675 src.getLineNumber(pos.getEndPosition(src.getEndPosTable())) == 1;
676 }
677
678 /**
679 * Ignores any recent documentation comments found by the scanner,
680 * such as those that cannot be associated with a nearby declaration.
681 */
682 private void ignoreDanglingComments() {
683 S.getDocComments().clear();
684 }
685
686 /* -------- source positions ------- */
687
688 protected void setErrorEndPos(int errPos) {
689 endPosTable.setErrorEndPos(errPos);
690 }
691
692 /**
693 * Store ending position for a tree, the value of which is the greater of
694 * last error position in {@link #endPosTable} and the given ending position.
695 * @param tree tree node
696 * @param endpos the ending position to associate with {@code tree}
697 * @return {@code tree}
698 */
699 protected <T extends JCTree> T storeEnd(T tree, int endpos) {
700 return endPosTable.storeEnd(tree, endpos);
701 }
702
703 /**
704 * Store current token's ending position for a tree, the value of which
705 * will be the greater of last error position in {@link #endPosTable}
706 * and the ending position of the current token.
707 * @param tree tree node
708 */
709 protected <T extends JCTree> T to(T tree) {
710 return storeEnd(tree, token.endPos);
711 }
712
713 /**
714 * Store current token's ending position for a tree, the value of which
715 * will be the greater of last error position in {@link #endPosTable}
716 * and the ending position of the previous token.
717 * @param tree tree node
718 */
719 protected <T extends JCTree> T toP(T tree) {
720 return storeEnd(tree, S.prevToken().endPos);
721 }
722
723 /** Get the start position for a tree node. The start position is
724 * defined to be the position of the first character of the first
725 * token of the node's source text.
726 * @param tree The tree node
727 */
728 public int getStartPos(JCTree tree) {
729 return TreeInfo.getStartPos(tree);
730 }
731
732 /**
733 * Get the end position for a tree node. The end position is
734 * defined to be the position of the last character of the last
735 * token of the node's source text. Returns Position.NOPOS if end
736 * positions are not generated or the position is otherwise not
737 * found.
738 * @param tree The tree node
739 */
740 public int getEndPos(JCTree tree) {
741 return endPosTable.getEndPos(tree);
742 }
743
744
745
746 /* ---------- parsing -------------- */
747
748 /**
749 * Ident = IDENTIFIER
750 */
751 public Name ident() {
752 return ident(false);
753 }
754
755 protected Name ident(boolean allowClass) {
756 return ident(allowClass, false);
757 }
758
759 public Name identOrUnderscore() {
760 return ident(false, true);
761 }
762
763 protected Name ident(boolean allowClass, boolean asVariable) {
764 if (token.kind == IDENTIFIER) {
765 Name name = token.name();
766 nextToken();
767 return name;
768 } else if (token.kind == ASSERT) {
769 log.error(DiagnosticFlag.SYNTAX, token.pos, Errors.AssertAsIdentifier);
770 nextToken();
771 return names.error;
772 } else if (token.kind == ENUM) {
773 log.error(DiagnosticFlag.SYNTAX, token.pos, Errors.EnumAsIdentifier);
774 nextToken();
775 return names.error;
776 } else if (token.kind == THIS) {
777 if (allowThisIdent) {
778 Name name = token.name();
779 nextToken();
780 return name;
781 } else {
782 log.error(DiagnosticFlag.SYNTAX, token.pos, Errors.ThisAsIdentifier);
783 nextToken();
784 return names.error;
785 }
786 } else if (token.kind == UNDERSCORE) {
787 if (Feature.UNDERSCORE_IDENTIFIER.allowedInSource(source)) {
788 log.warning(token.pos, Warnings.UnderscoreAsIdentifier);
789 } else if (asVariable) {
790 checkSourceLevel(Feature.UNNAMED_VARIABLES);
791 if (peekToken(LBRACKET)) {
792 log.error(DiagnosticFlag.SYNTAX, token.pos, Errors.UseOfUnderscoreNotAllowedWithBrackets);
793 }
794 } else {
795 if (Feature.UNNAMED_VARIABLES.allowedInSource(source)) {
796 log.error(DiagnosticFlag.SYNTAX, token.pos, Errors.UseOfUnderscoreNotAllowedNonVariable);
797 } else {
798 log.error(DiagnosticFlag.SYNTAX, token.pos, Errors.UnderscoreAsIdentifier);
799 }
800 }
801 Name name = token.name();
802 nextToken();
803 return name;
804 } else {
805 accept(IDENTIFIER);
806 if (allowClass && token.kind == CLASS) {
807 nextToken();
808 return names._class;
809 }
810 return names.error;
811 }
812 }
813
814 /**
815 * Qualident = Ident { DOT [Annotations] Ident }
816 */
817 public JCExpression qualident(boolean allowAnnos) {
818 JCExpression t = toP(F.at(token.pos).Ident(ident()));
819 while (token.kind == DOT) {
820 int pos = token.pos;
821 nextToken();
822 List<JCAnnotation> tyannos = null;
823 if (allowAnnos) {
824 tyannos = typeAnnotationsOpt();
825 }
826 t = toP(F.at(pos).Select(t, ident()));
827 if (tyannos != null && tyannos.nonEmpty()) {
828 t = toP(F.at(tyannos.head.pos).AnnotatedType(tyannos, t));
829 }
830 }
831 return t;
832 }
833
834 JCExpression literal(Name prefix) {
835 return literal(prefix, token.pos);
836 }
837
838 /**
839 * Literal =
840 * INTLITERAL
841 * | LONGLITERAL
842 * | FLOATLITERAL
843 * | DOUBLELITERAL
844 * | CHARLITERAL
845 * | STRINGLITERAL
846 * | TRUE
847 * | FALSE
848 * | NULL
849 */
850 JCExpression literal(Name prefix, int pos) {
851 JCExpression t = errorTree;
852 switch (token.kind) {
853 case INTLITERAL:
854 try {
855 t = F.at(pos).Literal(
856 TypeTag.INT,
857 Convert.string2int(strval(prefix), token.radix()));
858 } catch (NumberFormatException ex) {
859 reportIntegralLiteralError(prefix, pos);
860 }
861 break;
862 case LONGLITERAL:
863 try {
864 t = F.at(pos).Literal(
865 TypeTag.LONG,
866 Long.valueOf(Convert.string2long(strval(prefix), token.radix())));
867 } catch (NumberFormatException ex) {
868 reportIntegralLiteralError(prefix, pos);
869 }
870 break;
871 case FLOATLITERAL: {
872 String proper = token.radix() == 16 ?
873 ("0x"+ token.stringVal()) :
874 token.stringVal();
875 Float n;
876 try {
877 n = Float.valueOf(proper);
878 } catch (NumberFormatException ex) {
879 // error already reported in scanner
880 n = Float.NaN;
881 }
882 if (n.floatValue() == 0.0f && !isZero(proper))
883 log.error(DiagnosticFlag.SYNTAX, token.pos, Errors.FpNumberTooSmall);
884 else if (n.floatValue() == Float.POSITIVE_INFINITY)
885 log.error(DiagnosticFlag.SYNTAX, token.pos, Errors.FpNumberTooLarge);
886 else
887 t = F.at(pos).Literal(TypeTag.FLOAT, n);
888 break;
889 }
890 case DOUBLELITERAL: {
891 String proper = token.radix() == 16 ?
892 ("0x"+ token.stringVal()) :
893 token.stringVal();
894 Double n;
895 try {
896 n = Double.valueOf(proper);
897 } catch (NumberFormatException ex) {
898 // error already reported in scanner
899 n = Double.NaN;
900 }
901 if (n.doubleValue() == 0.0d && !isZero(proper))
902 log.error(DiagnosticFlag.SYNTAX, token.pos, Errors.FpNumberTooSmall);
903 else if (n.doubleValue() == Double.POSITIVE_INFINITY)
904 log.error(DiagnosticFlag.SYNTAX, token.pos, Errors.FpNumberTooLarge);
905 else
906 t = F.at(pos).Literal(TypeTag.DOUBLE, n);
907 break;
908 }
909 case CHARLITERAL:
910 t = F.at(pos).Literal(
911 TypeTag.CHAR,
912 token.stringVal().charAt(0) + 0);
913 break;
914 case STRINGLITERAL:
915 t = F.at(pos).Literal(
916 TypeTag.CLASS,
917 token.stringVal());
918 break;
919 case TRUE: case FALSE:
920 t = F.at(pos).Literal(
921 TypeTag.BOOLEAN,
922 (token.kind == TRUE ? 1 : 0));
923 break;
924 case NULL:
925 t = F.at(pos).Literal(
926 TypeTag.BOT,
927 null);
928 break;
929 default:
930 Assert.error();
931 }
932 if (t == errorTree)
933 t = F.at(pos).Erroneous();
934 storeEnd(t, token.endPos);
935 nextToken();
936 return t;
937 }
938 //where
939 boolean isZero(String s) {
940 char[] cs = s.toCharArray();
941 int base = ((cs.length > 1 && Character.toLowerCase(cs[1]) == 'x') ? 16 : 10);
942 int i = ((base==16) ? 2 : 0);
943 while (i < cs.length && (cs[i] == '0' || cs[i] == '.')) i++;
944 return !(i < cs.length && (Character.digit(cs[i], base) > 0));
945 }
946
947 String strval(Name prefix) {
948 String s = token.stringVal();
949 return prefix.isEmpty() ? s : prefix + s;
950 }
951 void reportIntegralLiteralError(Name prefix, int pos) {
952 int radix = token.radix();
953 if (radix == 2 || radix == 8) {
954 //attempt to produce more user-friendly error message for
955 //binary and octal literals with wrong digits:
956 String value = strval(prefix);
957 char[] cs = value.toCharArray();
958 for (int i = 0; i < cs.length; i++) {
959 char c = cs[i];
960 int d = Character.digit(c, radix);
961 if (d == (-1)) {
962 Error err = radix == 2 ? Errors.IllegalDigitInBinaryLiteral
963 : Errors.IllegalDigitInOctalLiteral;
964 log.error(DiagnosticFlag.SYNTAX,
965 token.pos + i,
966 err);
967 return ;
968 }
969 }
970 }
971 log.error(DiagnosticFlag.SYNTAX, token.pos, Errors.IntNumberTooLarge(strval(prefix)));
972 }
973
974 /** terms can be either expressions or types.
975 */
976 public JCExpression parseExpression() {
977 return term(EXPR);
978 }
979
980 /** parses patterns.
981 */
982 public JCPattern parsePattern(int pos, JCModifiers mods, JCExpression parsedType,
983 boolean allowVar, boolean checkGuard) {
984 JCPattern pattern;
985 mods = mods != null ? mods : optFinal(0);
986 JCExpression e;
987 if (token.kind == UNDERSCORE && parsedType == null) {
988 nextToken();
989 checkSourceLevel(Feature.UNNAMED_VARIABLES);
990 pattern = toP(F.at(token.pos).AnyPattern());
991 }
992 else {
993 int varTypePos = Position.NOPOS;
994 if (parsedType == null) {
995 boolean var = token.kind == IDENTIFIER && token.name() == names.var;
996 e = unannotatedType(allowVar, TYPE | NOLAMBDA);
997 if (var) {
998 varTypePos = e.pos;
999 e = null;
1000 }
1001 } else {
1002 e = parsedType;
1003 }
1004 if (token.kind == LPAREN) {
1005 //deconstruction pattern:
1006 checkSourceLevel(Feature.RECORD_PATTERNS);
1007 ListBuffer<JCPattern> nested = new ListBuffer<>();
1008 if (!peekToken(RPAREN)) {
1009 do {
1010 nextToken();
1011 JCPattern nestedPattern = parsePattern(token.pos, null, null, true, false);
1012 nested.append(nestedPattern);
1013 } while (token.kind == COMMA);
1014 } else {
1015 nextToken();
1016 }
1017 accept(RPAREN);
1018 pattern = toP(F.at(pos).RecordPattern(e, nested.toList()));
1019 if (mods.annotations.nonEmpty()) {
1020 log.error(mods.annotations.head.pos(), Errors.RecordPatternsAnnotationsNotAllowed);
1021 }
1022 checkNoMods(pos, mods.flags & Flags.FINAL);
1023 new TreeScanner() {
1024 @Override
1025 public void visitAnnotatedType(JCAnnotatedType tree) {
1026 log.error(tree.pos(), Errors.RecordPatternsAnnotationsNotAllowed);
1027 }
1028 }.scan(e);
1029 } else {
1030 //type test pattern:
1031 int varPos = token.pos;
1032 Name name = identOrUnderscore();
1033 if (Feature.UNNAMED_VARIABLES.allowedInSource(source) && name == names.underscore) {
1034 name = names.empty;
1035 }
1036 JCVariableDecl var = toP(F.at(varPos).VarDef(mods, name, e, null,
1037 varTypePos != Position.NOPOS ? JCVariableDecl.DeclKind.VAR : JCVariableDecl.DeclKind.EXPLICIT,
1038 varTypePos));
1039 if (e == null) {
1040 if (var.name == names.underscore && !allowVar) {
1041 log.error(DiagnosticFlag.SYNTAX, varPos, Errors.UseOfUnderscoreNotAllowed);
1042 }
1043 }
1044 pattern = toP(F.at(pos).BindingPattern(var));
1045 }
1046 }
1047 return pattern;
1048 }
1049
1050 /**
1051 * parses (optional) type annotations followed by a type. If the
1052 * annotations are present before the type and are not consumed during array
1053 * parsing, this method returns a {@link JCAnnotatedType} consisting of
1054 * these annotations and the underlying type. Otherwise, it returns the
1055 * underlying type.
1056 *
1057 * <p>
1058 *
1059 * Note that this method sets {@code mode} to {@code TYPE} first, before
1060 * parsing annotations.
1061 */
1062 public JCExpression parseType() {
1063 return parseType(false);
1064 }
1065
1066 public JCExpression parseType(boolean allowVar) {
1067 List<JCAnnotation> annotations = typeAnnotationsOpt();
1068 return parseType(allowVar, annotations);
1069 }
1070
1071 public JCExpression parseType(boolean allowVar, List<JCAnnotation> annotations) {
1072 JCExpression result = unannotatedType(allowVar);
1073
1074 if (annotations.nonEmpty()) {
1075 result = insertAnnotationsToMostInner(result, annotations, false);
1076 }
1077
1078 return result;
1079 }
1080
1081 protected JCExpression parseIntersectionType(int pos, JCExpression firstType) {
1082 JCExpression t = firstType;
1083 int pos1 = pos;
1084 List<JCExpression> targets = List.of(t);
1085 while (token.kind == AMP) {
1086 accept(AMP);
1087 targets = targets.prepend(parseType());
1088 }
1089 if (targets.length() > 1) {
1090 t = toP(F.at(pos1).TypeIntersection(targets.reverse()));
1091 }
1092 return t;
1093 }
1094
1095 public JCExpression unannotatedType(boolean allowVar) {
1096 return unannotatedType(allowVar, TYPE);
1097 }
1098
1099 public JCExpression unannotatedType(boolean allowVar, int newmode) {
1100 JCExpression result = term(newmode);
1101 Name restrictedTypeName = restrictedTypeName(result, !allowVar);
1102
1103 if (restrictedTypeName != null && (!allowVar || restrictedTypeName != names.var)) {
1104 syntaxError(result.pos, Errors.RestrictedTypeNotAllowedHere(restrictedTypeName));
1105 }
1106
1107 if ((lastmode & TYPE) == 0) {
1108 //if the mode was switched to expression while expecting type, wrap with Erroneous:
1109 result = F.Erroneous(List.of(result));
1110 }
1111
1112 return result;
1113 }
1114
1115
1116
1117 protected JCExpression term(int newmode) {
1118 int prevmode = mode;
1119 setMode(newmode);
1120 JCExpression t = term();
1121 setLastMode(mode);
1122 setMode(prevmode);
1123 return t;
1124 }
1125
1126 /**
1127 * {@literal
1128 * Expression = Expression1 [ExpressionRest]
1129 * ExpressionRest = [AssignmentOperator Expression1]
1130 * AssignmentOperator = "=" | "+=" | "-=" | "*=" | "/=" |
1131 * "&=" | "|=" | "^=" |
1132 * "%=" | "<<=" | ">>=" | ">>>="
1133 * Type = Type1
1134 * TypeNoParams = TypeNoParams1
1135 * StatementExpression = Expression
1136 * ConstantExpression = Expression
1137 * }
1138 */
1139 JCExpression term() {
1140 JCExpression t = term1();
1141 if (isMode(EXPR) &&
1142 (token.kind == EQ || PLUSEQ.compareTo(token.kind) <= 0 && token.kind.compareTo(GTGTGTEQ) <= 0))
1143 return termRest(t);
1144 else
1145 return t;
1146 }
1147
1148 JCExpression termRest(JCExpression t) {
1149 switch (token.kind) {
1150 case EQ: {
1151 int pos = token.pos;
1152 nextToken();
1153 selectExprMode();
1154 JCExpression t1 = term();
1155 return toP(F.at(pos).Assign(t, t1));
1156 }
1157 case PLUSEQ:
1158 case SUBEQ:
1159 case STAREQ:
1160 case SLASHEQ:
1161 case PERCENTEQ:
1162 case AMPEQ:
1163 case BAREQ:
1164 case CARETEQ:
1165 case LTLTEQ:
1166 case GTGTEQ:
1167 case GTGTGTEQ:
1168 int pos = token.pos;
1169 TokenKind tk = token.kind;
1170 nextToken();
1171 selectExprMode();
1172 JCExpression t1 = term();
1173 return F.at(pos).Assignop(optag(tk), t, t1);
1174 default:
1175 return t;
1176 }
1177 }
1178
1179 /** Expression1 = Expression2 [Expression1Rest]
1180 * Type1 = Type2
1181 * TypeNoParams1 = TypeNoParams2
1182 */
1183 JCExpression term1() {
1184 JCExpression t = term2();
1185 if (isMode(EXPR) && token.kind == QUES) {
1186 selectExprMode();
1187 return term1Rest(t);
1188 } else {
1189 return t;
1190 }
1191 }
1192
1193 /** Expression1Rest = ["?" Expression ":" Expression1]
1194 */
1195 JCExpression term1Rest(JCExpression t) {
1196 if (token.kind == QUES) {
1197 int pos = token.pos;
1198 nextToken();
1199 JCExpression t1 = term();
1200 accept(COLON);
1201 JCExpression t2 = term1();
1202 return F.at(pos).Conditional(t, t1, t2);
1203 } else {
1204 return t;
1205 }
1206 }
1207
1208 /** Expression2 = Expression3 [Expression2Rest]
1209 * Type2 = Type3
1210 * TypeNoParams2 = TypeNoParams3
1211 */
1212 JCExpression term2() {
1213 JCExpression t = term3();
1214 if (isMode(EXPR) && prec(token.kind) >= TreeInfo.orPrec) {
1215 selectExprMode();
1216 return term2Rest(t, TreeInfo.orPrec);
1217 } else {
1218 return t;
1219 }
1220 }
1221
1222 /* Expression2Rest = {infixop Expression3}
1223 * | Expression3 instanceof Type
1224 * | Expression3 instanceof Pattern
1225 * infixop = "||"
1226 * | "&&"
1227 * | "|"
1228 * | "^"
1229 * | "&"
1230 * | "==" | "!="
1231 * | "<" | ">" | "<=" | ">="
1232 * | "<<" | ">>" | ">>>"
1233 * | "+" | "-"
1234 * | "*" | "/" | "%"
1235 */
1236 JCExpression term2Rest(JCExpression t, int minprec) {
1237 JCExpression[] odStack = newOdStack();
1238 Token[] opStack = newOpStack();
1239
1240 // optimization, was odStack = new Tree[...]; opStack = new Tree[...];
1241 int top = 0;
1242 odStack[0] = t;
1243 int startPos = token.pos;
1244 Token topOp = Tokens.DUMMY;
1245 while (prec(token.kind) >= minprec) {
1246 opStack[top] = topOp;
1247
1248 if (token.kind == INSTANCEOF) {
1249 int pos = token.pos;
1250 nextToken();
1251 JCTree pattern;
1252 if (token.kind == LPAREN) {
1253 checkSourceLevel(token.pos, Feature.PATTERN_SWITCH);
1254 pattern = parsePattern(token.pos, null, null, false, false);
1255 } else {
1256 int patternPos = token.pos;
1257 JCModifiers mods = optFinal(0);
1258 int typePos = token.pos;
1259 JCExpression type = unannotatedType(false);
1260 if (token.kind == IDENTIFIER) {
1261 checkSourceLevel(token.pos, Feature.PATTERN_MATCHING_IN_INSTANCEOF);
1262 pattern = parsePattern(patternPos, mods, type, false, false);
1263 } else if (token.kind == LPAREN) {
1264 pattern = parsePattern(patternPos, mods, type, false, false);
1265 } else if (token.kind == UNDERSCORE) {
1266 checkSourceLevel(token.pos, Feature.UNNAMED_VARIABLES);
1267 pattern = parsePattern(patternPos, mods, type, false, false);
1268 } else {
1269 checkNoMods(typePos, mods.flags & ~Flags.DEPRECATED);
1270 if (mods.annotations.nonEmpty()) {
1271 List<JCAnnotation> typeAnnos =
1272 mods.annotations
1273 .map(decl -> {
1274 JCAnnotation typeAnno = F.at(decl.pos)
1275 .TypeAnnotation(decl.annotationType,
1276 decl.args);
1277 endPosTable.replaceTree(decl, typeAnno);
1278 return typeAnno;
1279 });
1280 type = insertAnnotationsToMostInner(type, typeAnnos, false);
1281 }
1282 pattern = type;
1283 }
1284 }
1285 odStack[top] = F.at(pos).TypeTest(odStack[top], pattern);
1286 } else {
1287 topOp = token;
1288 nextToken();
1289 top++;
1290 odStack[top] = term3();
1291 }
1292 while (top > 0 && prec(topOp.kind) >= prec(token.kind)) {
1293 odStack[top - 1] = F.at(topOp.pos).Binary(optag(topOp.kind), odStack[top - 1], odStack[top]);
1294 top--;
1295 topOp = opStack[top];
1296 }
1297 }
1298 Assert.check(top == 0);
1299 t = odStack[0];
1300
1301 if (t.hasTag(JCTree.Tag.PLUS)) {
1302 t = foldStrings(t);
1303 }
1304
1305 odStackSupply.add(odStack);
1306 opStackSupply.add(opStack);
1307 return t;
1308 }
1309 //where
1310 /** If tree is a concatenation of string literals, replace it
1311 * by a single literal representing the concatenated string.
1312 */
1313 protected JCExpression foldStrings(JCExpression tree) {
1314 if (!allowStringFolding)
1315 return tree;
1316 ListBuffer<JCExpression> opStack = new ListBuffer<>();
1317 ListBuffer<JCLiteral> litBuf = new ListBuffer<>();
1318 boolean needsFolding = false;
1319 JCExpression curr = tree;
1320 while (true) {
1321 if (curr.hasTag(JCTree.Tag.PLUS)) {
1322 JCBinary op = (JCBinary)curr;
1323 needsFolding |= foldIfNeeded(op.rhs, litBuf, opStack, false);
1324 curr = op.lhs;
1325 } else {
1326 needsFolding |= foldIfNeeded(curr, litBuf, opStack, true);
1327 break; //last one!
1328 }
1329 }
1330 if (needsFolding) {
1331 List<JCExpression> ops = opStack.toList();
1332 JCExpression res = ops.head;
1333 for (JCExpression op : ops.tail) {
1334 res = F.at(op.getStartPosition()).Binary(optag(TokenKind.PLUS), res, op);
1335 storeEnd(res, getEndPos(op));
1336 }
1337 return res;
1338 } else {
1339 return tree;
1340 }
1341 }
1342
1343 private boolean foldIfNeeded(JCExpression tree, ListBuffer<JCLiteral> litBuf,
1344 ListBuffer<JCExpression> opStack, boolean last) {
1345 JCLiteral str = stringLiteral(tree);
1346 if (str != null) {
1347 litBuf.prepend(str);
1348 return last && merge(litBuf, opStack);
1349 } else {
1350 boolean res = merge(litBuf, opStack);
1351 litBuf.clear();
1352 opStack.prepend(tree);
1353 return res;
1354 }
1355 }
1356
1357 boolean merge(ListBuffer<JCLiteral> litBuf, ListBuffer<JCExpression> opStack) {
1358 if (litBuf.isEmpty()) {
1359 return false;
1360 } else if (litBuf.size() == 1) {
1361 opStack.prepend(litBuf.first());
1362 return false;
1363 } else {
1364 JCExpression t = F.at(litBuf.first().getStartPosition()).Literal(TypeTag.CLASS,
1365 litBuf.stream().map(lit -> (String)lit.getValue()).collect(Collectors.joining()));
1366 storeEnd(t, litBuf.last().getEndPosition(endPosTable));
1367 opStack.prepend(t);
1368 return true;
1369 }
1370 }
1371
1372 private JCLiteral stringLiteral(JCTree tree) {
1373 if (tree.hasTag(LITERAL)) {
1374 JCLiteral lit = (JCLiteral)tree;
1375 if (lit.typetag == TypeTag.CLASS) {
1376 return lit;
1377 }
1378 }
1379 return null;
1380 }
1381
1382
1383 /** optimization: To save allocating a new operand/operator stack
1384 * for every binary operation, we use supplys.
1385 */
1386 ArrayList<JCExpression[]> odStackSupply = new ArrayList<>();
1387 ArrayList<Token[]> opStackSupply = new ArrayList<>();
1388
1389 private JCExpression[] newOdStack() {
1390 if (odStackSupply.isEmpty())
1391 return new JCExpression[infixPrecedenceLevels + 1];
1392 return odStackSupply.remove(odStackSupply.size() - 1);
1393 }
1394
1395 private Token[] newOpStack() {
1396 if (opStackSupply.isEmpty())
1397 return new Token[infixPrecedenceLevels + 1];
1398 return opStackSupply.remove(opStackSupply.size() - 1);
1399 }
1400
1401 /**
1402 * Expression3 = PrefixOp Expression3
1403 * | "(" Expr | TypeNoParams ")" Expression3
1404 * | Primary {Selector} {PostfixOp}
1405 *
1406 * {@literal
1407 * Primary = "(" Expression ")"
1408 * | Literal
1409 * | [TypeArguments] THIS [Arguments]
1410 * | [TypeArguments] SUPER SuperSuffix
1411 * | NEW [TypeArguments] Creator
1412 * | "(" Arguments ")" "->" ( Expression | Block )
1413 * | Ident "->" ( Expression | Block )
1414 * | [Annotations] Ident { "." [Annotations] Ident }
1415 * | Expression3 MemberReferenceSuffix
1416 * [ [Annotations] "[" ( "]" BracketsOpt "." CLASS | Expression "]" )
1417 * | Arguments
1418 * | "." ( CLASS | THIS | [TypeArguments] SUPER Arguments | NEW [TypeArguments] InnerCreator )
1419 * ]
1420 * | BasicType BracketsOpt "." CLASS
1421 * }
1422 *
1423 * PrefixOp = "++" | "--" | "!" | "~" | "+" | "-"
1424 * PostfixOp = "++" | "--"
1425 * Type3 = Ident { "." Ident } [TypeArguments] {TypeSelector} BracketsOpt
1426 * | BasicType
1427 * TypeNoParams3 = Ident { "." Ident } BracketsOpt
1428 * Selector = "." [TypeArguments] Ident [Arguments]
1429 * | "." THIS
1430 * | "." [TypeArguments] SUPER SuperSuffix
1431 * | "." NEW [TypeArguments] InnerCreator
1432 * | "[" Expression "]"
1433 * TypeSelector = "." Ident [TypeArguments]
1434 * SuperSuffix = Arguments | "." Ident [Arguments]
1435 */
1436 protected JCExpression term3() {
1437 int pos = token.pos;
1438 JCExpression t;
1439 int startMode = mode;
1440 List<JCExpression> typeArgs = typeArgumentsOpt(EXPR);
1441 switch (token.kind) {
1442 case QUES:
1443 if (isMode(TYPE) && isMode(TYPEARG) && !isMode(NOPARAMS)) {
1444 selectTypeMode();
1445 return typeArgument();
1446 } else
1447 return illegal();
1448 case PLUSPLUS: case SUBSUB: case BANG: case TILDE: case PLUS: case SUB:
1449 if (typeArgs == null && isMode(EXPR)) {
1450 TokenKind tk = token.kind;
1451 nextToken();
1452 selectExprMode();
1453 if (tk == SUB &&
1454 (token.kind == INTLITERAL || token.kind == LONGLITERAL) &&
1455 token.radix() == 10) {
1456 selectExprMode();
1457 t = literal(names.hyphen, pos);
1458 } else {
1459 t = term3();
1460 return F.at(pos).Unary(unoptag(tk), t);
1461 }
1462 } else return illegal();
1463 break;
1464 case LPAREN:
1465 if (typeArgs == null && isMode(EXPR)) {
1466 ParensResult pres = analyzeParens();
1467 switch (pres) {
1468 case CAST:
1469 accept(LPAREN);
1470 selectTypeMode();
1471 t = parseIntersectionType(pos, parseType());
1472 accept(RPAREN);
1473 selectExprMode();
1474 JCExpression t1 = term3();
1475 return F.at(pos).TypeCast(t, t1);
1476 case IMPLICIT_LAMBDA:
1477 case EXPLICIT_LAMBDA:
1478 t = lambdaExpressionOrStatement(true, pres == ParensResult.EXPLICIT_LAMBDA, pos);
1479 break;
1480 default: //PARENS
1481 accept(LPAREN);
1482 selectExprMode();
1483 t = termRest(term1Rest(term2Rest(term3(), TreeInfo.orPrec)));
1484 accept(RPAREN);
1485 t = toP(F.at(pos).Parens(t));
1486 break;
1487 }
1488 } else {
1489 return illegal();
1490 }
1491 break;
1492 case THIS:
1493 if (isMode(EXPR)) {
1494 selectExprMode();
1495 t = to(F.at(pos).Ident(names._this));
1496 nextToken();
1497 if (typeArgs == null)
1498 t = argumentsOpt(null, t);
1499 else
1500 t = arguments(typeArgs, t);
1501 typeArgs = null;
1502 } else return illegal();
1503 break;
1504 case SUPER:
1505 if (isMode(EXPR)) {
1506 selectExprMode();
1507 t = to(F.at(pos).Ident(names._super));
1508 t = superSuffix(typeArgs, t);
1509 typeArgs = null;
1510 } else return illegal();
1511 break;
1512 case INTLITERAL: case LONGLITERAL: case FLOATLITERAL: case DOUBLELITERAL:
1513 case CHARLITERAL: case STRINGLITERAL:
1514 case TRUE: case FALSE: case NULL:
1515 if (typeArgs == null && isMode(EXPR)) {
1516 selectExprMode();
1517 t = literal(names.empty);
1518 } else return illegal();
1519 break;
1520 case NEW:
1521 if (typeArgs != null) return illegal();
1522 if (isMode(EXPR)) {
1523 selectExprMode();
1524 nextToken();
1525 if (token.kind == LT) typeArgs = typeArguments(false);
1526 t = creator(pos, typeArgs);
1527 typeArgs = null;
1528 } else return illegal();
1529 break;
1530 case MONKEYS_AT:
1531 // Only annotated cast types and method references are valid
1532 List<JCAnnotation> typeAnnos = typeAnnotationsOpt();
1533 if (typeAnnos.isEmpty()) {
1534 // else there would be no '@'
1535 throw new AssertionError("Expected type annotations, but found none!");
1536 }
1537
1538 JCExpression expr = term3();
1539
1540 if (!isMode(TYPE)) {
1541 // Type annotations on class literals no longer legal
1542 switch (expr.getTag()) {
1543 case REFERENCE: {
1544 JCMemberReference mref = (JCMemberReference) expr;
1545 if (TreeInfo.isType(mref.expr, names)) {
1546 mref.expr = insertAnnotationsToMostInner(mref.expr, typeAnnos, false);
1547 } else {
1548 //the selector is not a type, error recovery:
1549 JCAnnotatedType annotatedType =
1550 toP(F.at(pos).AnnotatedType(typeAnnos, mref.expr));
1551 int termStart = getStartPos(mref.expr);
1552 mref.expr = syntaxError(termStart, List.of(annotatedType),
1553 Errors.IllegalStartOfType);
1554 }
1555 mref.pos = getStartPos(mref.expr);
1556 t = mref;
1557 break;
1558 }
1559 case SELECT: {
1560 JCFieldAccess sel = (JCFieldAccess) expr;
1561
1562 if (sel.name != names._class) {
1563 return illegal();
1564 } else {
1565 log.error(token.pos, Errors.NoAnnotationsOnDotClass);
1566 return expr;
1567 }
1568 }
1569 default:
1570 return illegal(typeAnnos.head.pos);
1571 }
1572
1573 } else {
1574 // Type annotations targeting a cast
1575 t = insertAnnotationsToMostInner(expr, typeAnnos, false);
1576 }
1577 break;
1578 case UNDERSCORE: case IDENTIFIER: case ASSERT: case ENUM:
1579 if (typeArgs != null) return illegal();
1580 if (isMode(EXPR) && !isMode(NOLAMBDA) && peekToken(ARROW)) {
1581 t = lambdaExpressionOrStatement(false, false, pos);
1582 } else {
1583 t = toP(F.at(token.pos).Ident(ident()));
1584 loop: while (true) {
1585 pos = token.pos;
1586 final List<JCAnnotation> annos = typeAnnotationsOpt();
1587
1588 // need to report an error later if LBRACKET is for array
1589 // index access rather than array creation level
1590 if (!annos.isEmpty() && token.kind != LBRACKET && token.kind != ELLIPSIS)
1591 return illegal(annos.head.pos);
1592
1593 switch (token.kind) {
1594 case LBRACKET:
1595 nextToken();
1596 if (token.kind == RBRACKET) {
1597 nextToken();
1598 t = bracketsOpt(t);
1599 t = toP(F.at(pos).TypeArray(t));
1600 if (annos.nonEmpty()) {
1601 t = toP(F.at(pos).AnnotatedType(annos, t));
1602 }
1603 t = bracketsSuffix(t);
1604 } else {
1605 if (isMode(EXPR)) {
1606 selectExprMode();
1607 JCExpression t1 = term();
1608 if (!annos.isEmpty()) t = illegal(annos.head.pos);
1609 t = to(F.at(pos).Indexed(t, t1));
1610 }
1611 accept(RBRACKET);
1612 }
1613 break loop;
1614 case LPAREN:
1615 if (isMode(EXPR)) {
1616 selectExprMode();
1617 t = arguments(typeArgs, t);
1618 if (!annos.isEmpty()) t = illegal(annos.head.pos);
1619 typeArgs = null;
1620 }
1621 break loop;
1622 case DOT:
1623 nextToken();
1624 if (token.kind == TokenKind.IDENTIFIER && typeArgs != null) {
1625 return illegal();
1626 }
1627 int prevmode = mode;
1628 setMode(mode & ~NOPARAMS);
1629 typeArgs = typeArgumentsOpt(EXPR);
1630 setMode(prevmode);
1631 if (isMode(EXPR)) {
1632 switch (token.kind) {
1633 case CLASS:
1634 if (typeArgs != null) return illegal();
1635 selectExprMode();
1636 t = to(F.at(pos).Select(t, names._class));
1637 nextToken();
1638 break loop;
1639 case THIS:
1640 if (typeArgs != null) return illegal();
1641 selectExprMode();
1642 t = to(F.at(pos).Select(t, names._this));
1643 nextToken();
1644 break loop;
1645 case SUPER:
1646 selectExprMode();
1647 t = to(F.at(pos).Select(t, names._super));
1648 t = superSuffix(typeArgs, t);
1649 typeArgs = null;
1650 break loop;
1651 case NEW:
1652 if (typeArgs != null) return illegal();
1653 selectExprMode();
1654 int pos1 = token.pos;
1655 nextToken();
1656 if (token.kind == LT) typeArgs = typeArguments(false);
1657 t = innerCreator(pos1, typeArgs, t);
1658 typeArgs = null;
1659 break loop;
1660 }
1661 }
1662
1663 List<JCAnnotation> tyannos = null;
1664 if (isMode(TYPE) && token.kind == MONKEYS_AT) {
1665 tyannos = typeAnnotationsOpt();
1666 }
1667 // typeArgs saved for next loop iteration.
1668 t = toP(F.at(pos).Select(t, ident()));
1669 if (token.pos <= endPosTable.errorEndPos &&
1670 token.kind == MONKEYS_AT) {
1671 //error recovery, case like:
1672 //int i = expr.<missing-ident>
1673 //@Deprecated
1674 if (typeArgs != null) illegal();
1675 return toP(t);
1676 }
1677 if (tyannos != null && tyannos.nonEmpty()) {
1678 t = toP(F.at(tyannos.head.pos).AnnotatedType(tyannos, t));
1679 }
1680 break;
1681 case ELLIPSIS:
1682 if (this.permitTypeAnnotationsPushBack) {
1683 this.typeAnnotationsPushedBack = annos;
1684 } else if (annos.nonEmpty()) {
1685 // Don't return here -- error recovery attempt
1686 illegal(annos.head.pos);
1687 }
1688 break loop;
1689 case LT:
1690 if (!isMode(TYPE) && isUnboundMemberRef()) {
1691 //this is an unbound method reference whose qualifier
1692 //is a generic type i.e. A<S>::m
1693 int pos1 = token.pos;
1694 accept(LT);
1695 ListBuffer<JCExpression> args = new ListBuffer<>();
1696 args.append(typeArgument());
1697 while (token.kind == COMMA) {
1698 nextToken();
1699 args.append(typeArgument());
1700 }
1701 accept(GT);
1702 t = toP(F.at(pos1).TypeApply(t, args.toList()));
1703 while (token.kind == DOT) {
1704 nextToken();
1705 selectTypeMode();
1706 t = toP(F.at(token.pos).Select(t, ident()));
1707 t = typeArgumentsOpt(t);
1708 }
1709 t = bracketsOpt(t);
1710 if (token.kind != COLCOL) {
1711 //method reference expected here
1712 t = illegal();
1713 }
1714 selectExprMode();
1715 return term3Rest(t, typeArgs);
1716 }
1717 break loop;
1718 default:
1719 break loop;
1720 }
1721 }
1722 }
1723 if (typeArgs != null) illegal();
1724 t = typeArgumentsOpt(t);
1725 break;
1726 case BYTE: case SHORT: case CHAR: case INT: case LONG: case FLOAT:
1727 case DOUBLE: case BOOLEAN:
1728 if (typeArgs != null) illegal();
1729 t = bracketsSuffix(bracketsOpt(basicType()));
1730 break;
1731 case VOID:
1732 if (typeArgs != null) illegal();
1733 if (isMode(EXPR)) {
1734 nextToken();
1735 if (token.kind == DOT) {
1736 JCPrimitiveTypeTree ti = toP(F.at(pos).TypeIdent(TypeTag.VOID));
1737 t = bracketsSuffix(ti);
1738 } else {
1739 return illegal(pos);
1740 }
1741 } else {
1742 // Support the corner case of myMethodHandle.<void>invoke() by passing
1743 // a void type (like other primitive types) to the next phase.
1744 // The error will be reported in Attr.attribTypes or Attr.visitApply.
1745 JCPrimitiveTypeTree ti = to(F.at(pos).TypeIdent(TypeTag.VOID));
1746 nextToken();
1747 return ti;
1748 //return illegal();
1749 }
1750 break;
1751 case SWITCH:
1752 checkSourceLevel(Feature.SWITCH_EXPRESSION);
1753 allowYieldStatement = true;
1754 int switchPos = token.pos;
1755 nextToken();
1756 JCExpression selector = parExpression();
1757 accept(LBRACE);
1758 ListBuffer<JCCase> cases = new ListBuffer<>();
1759 while (true) {
1760 pos = token.pos;
1761 switch (token.kind) {
1762 case CASE:
1763 case DEFAULT:
1764 cases.appendList(switchExpressionStatementGroup());
1765 break;
1766 case RBRACE: case EOF:
1767 JCSwitchExpression e = to(F.at(switchPos).SwitchExpression(selector,
1768 cases.toList()));
1769 e.bracePos = token.pos;
1770 accept(RBRACE);
1771 return e;
1772 default:
1773 nextToken(); // to ensure progress
1774 syntaxError(pos, Errors.Expected3(CASE, DEFAULT, RBRACE));
1775 }
1776 }
1777 // Not reachable.
1778 default:
1779 if (typeArgs != null && (startMode & TYPE) != 0) {
1780 return F.at(pos).TypeApply(F.Erroneous(), typeArgs);
1781 }
1782 return illegal();
1783 }
1784 return term3Rest(t, typeArgs);
1785 }
1786
1787 private List<JCCase> switchExpressionStatementGroup() {
1788 ListBuffer<JCCase> caseExprs = new ListBuffer<>();
1789 int casePos = token.pos;
1790 ListBuffer<JCCaseLabel> pats = new ListBuffer<>();
1791
1792 if (token.kind == DEFAULT) {
1793 nextToken();
1794 pats.append(toP(F.at(casePos).DefaultCaseLabel()));
1795 } else {
1796 accept(CASE);
1797 boolean allowDefault = false;
1798 while (true) {
1799 JCCaseLabel label = parseCaseLabel(allowDefault);
1800 pats.append(label);
1801 if (token.kind != COMMA) break;
1802 checkSourceLevel(Feature.SWITCH_MULTIPLE_CASE_LABELS);
1803 nextToken();
1804 allowDefault = TreeInfo.isNullCaseLabel(label);
1805 };
1806 }
1807 JCExpression guard = parseGuard(pats.last());
1808 List<JCStatement> stats = null;
1809 JCTree body = null;
1810 CaseTree.CaseKind kind;
1811 switch (token.kind) {
1812 case ARROW:
1813 checkSourceLevel(Feature.SWITCH_RULE);
1814 nextToken();
1815 if (token.kind == TokenKind.THROW || token.kind == TokenKind.LBRACE) {
1816 stats = List.of(parseStatement());
1817 body = stats.head;
1818 kind = JCCase.RULE;
1819 } else {
1820 JCExpression value = parseExpression();
1821 stats = List.of(to(F.at(value).Yield(value)));
1822 body = value;
1823 kind = JCCase.RULE;
1824 accept(SEMI);
1825 }
1826 break;
1827 default:
1828 accept(COLON, tk -> Errors.Expected2(COLON, ARROW));
1829 stats = blockStatements();
1830 kind = JCCase.STATEMENT;
1831 break;
1832 }
1833 caseExprs.append(toP(F.at(casePos).Case(kind, pats.toList(), guard, stats, body)));
1834 return caseExprs.toList();
1835 }
1836
1837 JCExpression term3Rest(JCExpression t, List<JCExpression> typeArgs) {
1838 if (typeArgs != null) illegal();
1839 while (true) {
1840 int pos1 = token.pos;
1841 final List<JCAnnotation> annos = typeAnnotationsOpt();
1842
1843 if (token.kind == LBRACKET) {
1844 nextToken();
1845 if (isMode(TYPE)) {
1846 int prevmode = mode;
1847 selectTypeMode();
1848 if (token.kind == RBRACKET) {
1849 nextToken();
1850 t = bracketsOpt(t);
1851 t = toP(F.at(pos1).TypeArray(t));
1852 if (token.kind == COLCOL) {
1853 selectExprMode();
1854 continue;
1855 }
1856 if (annos.nonEmpty()) {
1857 t = toP(F.at(pos1).AnnotatedType(annos, t));
1858 }
1859 return t;
1860 }
1861 setMode(prevmode);
1862 }
1863 if (isMode(EXPR)) {
1864 selectExprMode();
1865 JCExpression t1 = term();
1866 t = to(F.at(pos1).Indexed(t, t1));
1867 }
1868 accept(RBRACKET);
1869 } else if (token.kind == DOT) {
1870 nextToken();
1871 typeArgs = typeArgumentsOpt(EXPR);
1872 if (token.kind == SUPER && isMode(EXPR)) {
1873 selectExprMode();
1874 t = to(F.at(pos1).Select(t, names._super));
1875 nextToken();
1876 t = arguments(typeArgs, t);
1877 typeArgs = null;
1878 } else if (token.kind == NEW && isMode(EXPR)) {
1879 if (typeArgs != null) return illegal();
1880 selectExprMode();
1881 int pos2 = token.pos;
1882 nextToken();
1883 if (token.kind == LT) typeArgs = typeArguments(false);
1884 t = innerCreator(pos2, typeArgs, t);
1885 typeArgs = null;
1886 } else {
1887 List<JCAnnotation> tyannos = null;
1888 if (isMode(TYPE) && token.kind == MONKEYS_AT) {
1889 // is the mode check needed?
1890 tyannos = typeAnnotationsOpt();
1891 }
1892 t = toP(F.at(pos1).Select(t, ident(true)));
1893 if (token.pos <= endPosTable.errorEndPos &&
1894 token.kind == MONKEYS_AT) {
1895 //error recovery, case like:
1896 //int i = expr.<missing-ident>
1897 //@Deprecated
1898 break;
1899 }
1900 if (tyannos != null && tyannos.nonEmpty()) {
1901 t = toP(F.at(tyannos.head.pos).AnnotatedType(tyannos, t));
1902 }
1903 t = argumentsOpt(typeArgs, typeArgumentsOpt(t));
1904 typeArgs = null;
1905 }
1906 } else if (isMode(EXPR) && token.kind == COLCOL) {
1907 selectExprMode();
1908 if (typeArgs != null) return illegal();
1909 accept(COLCOL);
1910 t = memberReferenceSuffix(pos1, t);
1911 } else {
1912 if (!annos.isEmpty()) {
1913 if (permitTypeAnnotationsPushBack)
1914 typeAnnotationsPushedBack = annos;
1915 else
1916 return illegal(annos.head.pos);
1917 }
1918 break;
1919 }
1920 }
1921 while ((token.kind == PLUSPLUS || token.kind == SUBSUB) && isMode(EXPR)) {
1922 selectExprMode();
1923 t = to(F.at(token.pos).Unary(
1924 token.kind == PLUSPLUS ? POSTINC : POSTDEC, t));
1925 nextToken();
1926 }
1927 return toP(t);
1928 }
1929
1930 /**
1931 * If we see an identifier followed by a '<' it could be an unbound
1932 * method reference or a binary expression. To disambiguate, look for a
1933 * matching '>' and see if the subsequent terminal is either '.' or '::'.
1934 */
1935 @SuppressWarnings("fallthrough")
1936 boolean isUnboundMemberRef() {
1937 int pos = 0, depth = 0;
1938 outer: for (Token t = S.token(pos) ; ; t = S.token(++pos)) {
1939 switch (t.kind) {
1940 case IDENTIFIER: case UNDERSCORE: case QUES: case EXTENDS: case SUPER:
1941 case DOT: case RBRACKET: case LBRACKET: case COMMA:
1942 case BYTE: case SHORT: case INT: case LONG: case FLOAT:
1943 case DOUBLE: case BOOLEAN: case CHAR:
1944 case MONKEYS_AT:
1945 break;
1946
1947 case LPAREN:
1948 // skip annotation values
1949 int nesting = 0;
1950 for (; ; pos++) {
1951 TokenKind tk2 = S.token(pos).kind;
1952 switch (tk2) {
1953 case EOF:
1954 return false;
1955 case LPAREN:
1956 nesting++;
1957 break;
1958 case RPAREN:
1959 nesting--;
1960 if (nesting == 0) {
1961 continue outer;
1962 }
1963 break;
1964 }
1965 }
1966
1967 case LT:
1968 depth++; break;
1969 case GTGTGT:
1970 depth--;
1971 case GTGT:
1972 depth--;
1973 case GT:
1974 depth--;
1975 if (depth == 0) {
1976 TokenKind nextKind = S.token(pos + 1).kind;
1977 return
1978 nextKind == TokenKind.DOT ||
1979 nextKind == TokenKind.LBRACKET ||
1980 nextKind == TokenKind.COLCOL;
1981 }
1982 break;
1983 default:
1984 return false;
1985 }
1986 }
1987 }
1988
1989 /**
1990 * If we see an identifier followed by a '<' it could be an unbound
1991 * method reference or a binary expression. To disambiguate, look for a
1992 * matching '>' and see if the subsequent terminal is either '.' or '::'.
1993 */
1994 @SuppressWarnings("fallthrough")
1995 ParensResult analyzeParens() {
1996 int depth = 0;
1997 boolean type = false;
1998 ParensResult defaultResult = ParensResult.PARENS;
1999 outer: for (int lookahead = 0; ; lookahead++) {
2000 TokenKind tk = S.token(lookahead).kind;
2001 switch (tk) {
2002 case COMMA:
2003 type = true;
2004 case EXTENDS: case SUPER: case DOT: case AMP:
2005 //skip
2006 break;
2007 case QUES:
2008 if (peekToken(lookahead, EXTENDS) ||
2009 peekToken(lookahead, SUPER)) {
2010 //wildcards
2011 type = true;
2012 }
2013 break;
2014 case BYTE: case SHORT: case INT: case LONG: case FLOAT:
2015 case DOUBLE: case BOOLEAN: case CHAR: case VOID:
2016 if (peekToken(lookahead, RPAREN)) {
2017 //Type, ')' -> cast
2018 return ParensResult.CAST;
2019 } else if (peekToken(lookahead, LAX_IDENTIFIER)) {
2020 //Type, Identifier/'_'/'assert'/'enum' -> explicit lambda
2021 return ParensResult.EXPLICIT_LAMBDA;
2022 }
2023 break;
2024 case LPAREN:
2025 if (lookahead != 0) {
2026 // '(' in a non-starting position -> parens
2027 return ParensResult.PARENS;
2028 } else if (peekToken(lookahead, RPAREN)) {
2029 // '(', ')' -> explicit lambda
2030 return ParensResult.EXPLICIT_LAMBDA;
2031 }
2032 break;
2033 case RPAREN:
2034 // if we have seen something that looks like a type,
2035 // then it's a cast expression
2036 if (type) return ParensResult.CAST;
2037 // otherwise, disambiguate cast vs. parenthesized expression
2038 // based on subsequent token.
2039 switch (S.token(lookahead + 1).kind) {
2040 /*case PLUSPLUS: case SUBSUB: */
2041 case BANG: case TILDE:
2042 case LPAREN: case THIS: case SUPER:
2043 case INTLITERAL: case LONGLITERAL: case FLOATLITERAL:
2044 case DOUBLELITERAL: case CHARLITERAL: case STRINGLITERAL:
2045 case STRINGFRAGMENT:
2046 case TRUE: case FALSE: case NULL:
2047 case NEW: case IDENTIFIER: case ASSERT: case ENUM: case UNDERSCORE:
2048 case SWITCH:
2049 case BYTE: case SHORT: case CHAR: case INT:
2050 case LONG: case FLOAT: case DOUBLE: case BOOLEAN: case VOID:
2051 return ParensResult.CAST;
2052 default:
2053 return defaultResult;
2054 }
2055 case UNDERSCORE:
2056 case ASSERT:
2057 case ENUM:
2058 case IDENTIFIER:
2059 if (peekToken(lookahead, LAX_IDENTIFIER)) {
2060 // Identifier, Identifier/'_'/'assert'/'enum' -> explicit lambda
2061 return ParensResult.EXPLICIT_LAMBDA;
2062 } else if (peekToken(lookahead, RPAREN, ARROW)) {
2063 // Identifier, ')' '->' -> implicit lambda
2064 return !isMode(NOLAMBDA) ? ParensResult.IMPLICIT_LAMBDA
2065 : ParensResult.PARENS;
2066 } else if (depth == 0 && peekToken(lookahead, COMMA)) {
2067 defaultResult = ParensResult.IMPLICIT_LAMBDA;
2068 }
2069 type = false;
2070 break;
2071 case FINAL:
2072 case ELLIPSIS:
2073 //those can only appear in explicit lambdas
2074 return ParensResult.EXPLICIT_LAMBDA;
2075 case MONKEYS_AT:
2076 type = true;
2077 lookahead = skipAnnotation(lookahead);
2078 break;
2079 case LBRACKET:
2080 if (peekToken(lookahead, RBRACKET, LAX_IDENTIFIER)) {
2081 // '[', ']', Identifier/'_'/'assert'/'enum' -> explicit lambda
2082 return ParensResult.EXPLICIT_LAMBDA;
2083 } else if (peekToken(lookahead, RBRACKET, RPAREN) ||
2084 peekToken(lookahead, RBRACKET, AMP)) {
2085 // '[', ']', ')' -> cast
2086 // '[', ']', '&' -> cast (intersection type)
2087 return ParensResult.CAST;
2088 } else if (peekToken(lookahead, RBRACKET)) {
2089 //consume the ']' and skip
2090 type = true;
2091 lookahead++;
2092 break;
2093 } else {
2094 return ParensResult.PARENS;
2095 }
2096 case LT:
2097 depth++; break;
2098 case GTGTGT:
2099 depth--;
2100 case GTGT:
2101 depth--;
2102 case GT:
2103 depth--;
2104 if (depth == 0) {
2105 if (peekToken(lookahead, RPAREN) ||
2106 peekToken(lookahead, AMP)) {
2107 // '>', ')' -> cast
2108 // '>', '&' -> cast
2109 return ParensResult.CAST;
2110 } else if (peekToken(lookahead, LAX_IDENTIFIER, COMMA) ||
2111 peekToken(lookahead, LAX_IDENTIFIER, RPAREN, ARROW) ||
2112 peekToken(lookahead, ELLIPSIS)) {
2113 // '>', Identifier/'_'/'assert'/'enum', ',' -> explicit lambda
2114 // '>', Identifier/'_'/'assert'/'enum', ')', '->' -> explicit lambda
2115 // '>', '...' -> explicit lambda
2116 return ParensResult.EXPLICIT_LAMBDA;
2117 }
2118 //it looks a type, but could still be (i) a cast to generic type,
2119 //(ii) an unbound method reference or (iii) an explicit lambda
2120 type = true;
2121 break;
2122 } else if (depth < 0) {
2123 //unbalanced '<', '>' - not a generic type
2124 return ParensResult.PARENS;
2125 }
2126 break;
2127 default:
2128 //this includes EOF
2129 return defaultResult;
2130 }
2131 }
2132 }
2133
2134 private int skipAnnotation(int lookahead) {
2135 lookahead += 1; //skip '@'
2136 while (peekToken(lookahead, DOT)) {
2137 lookahead += 2;
2138 }
2139 if (peekToken(lookahead, LPAREN)) {
2140 lookahead++;
2141 //skip annotation values
2142 int nesting = 0;
2143 for (; ; lookahead++) {
2144 TokenKind tk2 = S.token(lookahead).kind;
2145 switch (tk2) {
2146 case EOF:
2147 return lookahead;
2148 case LPAREN:
2149 nesting++;
2150 break;
2151 case RPAREN:
2152 nesting--;
2153 if (nesting == 0) {
2154 return lookahead;
2155 }
2156 break;
2157 }
2158 }
2159 }
2160 return lookahead;
2161 }
2162
2163 /** Accepts all identifier-like tokens */
2164 protected Predicate<TokenKind> LAX_IDENTIFIER = t -> t == IDENTIFIER || t == UNDERSCORE || t == ASSERT || t == ENUM;
2165
2166 enum ParensResult {
2167 CAST,
2168 EXPLICIT_LAMBDA,
2169 IMPLICIT_LAMBDA,
2170 PARENS
2171 }
2172
2173 JCExpression lambdaExpressionOrStatement(boolean hasParens, boolean explicitParams, int pos) {
2174 List<JCVariableDecl> params = explicitParams ?
2175 formalParameters(true, false) :
2176 implicitParameters(hasParens);
2177 if (explicitParams) {
2178 LambdaClassifier lambdaClassifier = new LambdaClassifier();
2179 for (JCVariableDecl param: params) {
2180 Name restrictedTypeName;
2181 if (param.vartype != null &&
2182 (restrictedTypeName = restrictedTypeName(param.vartype, false)) != null &&
2183 param.vartype.hasTag(TYPEARRAY)) {
2184 log.error(DiagnosticFlag.SYNTAX, param.pos,
2185 Feature.VAR_SYNTAX_IMPLICIT_LAMBDAS.allowedInSource(source)
2186 ? Errors.RestrictedTypeNotAllowedArray(restrictedTypeName) : Errors.RestrictedTypeNotAllowedHere(restrictedTypeName));
2187 }
2188 lambdaClassifier.addParameter(param);
2189 if (lambdaClassifier.result() == LambdaParameterKind.ERROR) {
2190 break;
2191 }
2192 }
2193 if (lambdaClassifier.diagFragment != null) {
2194 log.error(DiagnosticFlag.SYNTAX, pos, Errors.InvalidLambdaParameterDeclaration(lambdaClassifier.diagFragment));
2195 }
2196 for (JCVariableDecl param: params) {
2197 if (param.vartype != null
2198 && restrictedTypeName(param.vartype, true) != null) {
2199 checkSourceLevel(param.pos, Feature.VAR_SYNTAX_IMPLICIT_LAMBDAS);
2200 param.declKind = JCVariableDecl.DeclKind.VAR;
2201 param.typePos = TreeInfo.getStartPos(param.vartype);
2202 param.vartype = null;
2203 }
2204 }
2205 }
2206 return lambdaExpressionOrStatementRest(params, pos);
2207 }
2208
2209 enum LambdaParameterKind {
2210 VAR(0),
2211 EXPLICIT(1),
2212 IMPLICIT(2),
2213 ERROR(-1);
2214
2215 private final int index;
2216
2217 LambdaParameterKind(int index) {
2218 this.index = index;
2219 }
2220 }
2221
2222 private static final Fragment[][] decisionTable = new Fragment[][] {
2223 /* VAR EXPLICIT IMPLICIT */
2224 /* VAR */ {null, VarAndExplicitNotAllowed, VarAndImplicitNotAllowed},
2225 /* EXPLICIT */ {VarAndExplicitNotAllowed, null, ImplicitAndExplicitNotAllowed},
2226 /* IMPLICIT */ {VarAndImplicitNotAllowed, ImplicitAndExplicitNotAllowed, null},
2227 };
2228
2229 class LambdaClassifier {
2230 LambdaParameterKind kind;
2231 Fragment diagFragment;
2232
2233 /**
2234 * analyzeParens() has already classified the lambda as EXPLICIT_LAMBDA, due to
2235 * two consecutive identifiers. Because of that {@code (<explicit lambda>)}, the
2236 * parser will always attempt to parse a type, followed by a name. If the lambda
2237 * contains an illegal mix of implicit and explicit parameters, it is possible
2238 * for the parser to see a {@code ,} when expecting a name, in which case the
2239 * variable is created with an erroneous name. The logic below makes sure that
2240 * the lambda parameters are all declared with either an explicit type (e.g.
2241 * {@code String x}), or with an inferred type (using {@code var x}). Any other
2242 * combination is rejected.
2243 * */
2244 void addParameter(JCVariableDecl param) {
2245 Assert.check(param.vartype != null);
2246
2247 if (param.name == names.error) {
2248 reduce(LambdaParameterKind.IMPLICIT);
2249 }
2250 else if (restrictedTypeName(param.vartype, false) != null) {
2251 reduce(LambdaParameterKind.VAR);
2252 } else {
2253 reduce(LambdaParameterKind.EXPLICIT);
2254 }
2255 }
2256
2257 private void reduce(LambdaParameterKind newKind) {
2258 if (kind == null) {
2259 kind = newKind;
2260 } else if (kind != newKind && kind != LambdaParameterKind.ERROR) {
2261 LambdaParameterKind currentKind = kind;
2262 kind = LambdaParameterKind.ERROR;
2263 boolean varIndex = currentKind.index == LambdaParameterKind.VAR.index ||
2264 newKind.index == LambdaParameterKind.VAR.index;
2265 diagFragment = Feature.VAR_SYNTAX_IMPLICIT_LAMBDAS.allowedInSource(source) || !varIndex ?
2266 decisionTable[currentKind.index][newKind.index] : null;
2267 }
2268 }
2269
2270 LambdaParameterKind result() {
2271 return kind;
2272 }
2273 }
2274
2275 JCExpression lambdaExpressionOrStatementRest(List<JCVariableDecl> args, int pos) {
2276 accept(ARROW);
2277
2278 return token.kind == LBRACE ?
2279 lambdaStatement(args, pos, token.pos) :
2280 lambdaExpression(args, pos);
2281 }
2282
2283 JCExpression lambdaStatement(List<JCVariableDecl> args, int pos, int pos2) {
2284 JCBlock block = block(pos2, 0);
2285 return toP(F.at(pos).Lambda(args, block));
2286 }
2287
2288 JCExpression lambdaExpression(List<JCVariableDecl> args, int pos) {
2289 JCTree expr = parseExpression();
2290 return toP(F.at(pos).Lambda(args, expr));
2291 }
2292
2293 /** SuperSuffix = Arguments | "." [TypeArguments] Ident [Arguments]
2294 */
2295 JCExpression superSuffix(List<JCExpression> typeArgs, JCExpression t) {
2296 nextToken();
2297 if (token.kind == LPAREN || typeArgs != null) {
2298 t = arguments(typeArgs, t);
2299 } else if (token.kind == COLCOL) {
2300 if (typeArgs != null) return illegal();
2301 t = memberReferenceSuffix(t);
2302 } else {
2303 int pos = token.pos;
2304 accept(DOT);
2305 typeArgs = (token.kind == LT) ? typeArguments(false) : null;
2306 t = toP(F.at(pos).Select(t, ident()));
2307 t = argumentsOpt(typeArgs, t);
2308 }
2309 return t;
2310 }
2311
2312 /** BasicType = BYTE | SHORT | CHAR | INT | LONG | FLOAT | DOUBLE | BOOLEAN
2313 */
2314 JCPrimitiveTypeTree basicType() {
2315 JCPrimitiveTypeTree t = to(F.at(token.pos).TypeIdent(typetag(token.kind)));
2316 nextToken();
2317 return t;
2318 }
2319
2320 /** ArgumentsOpt = [ Arguments ]
2321 */
2322 JCExpression argumentsOpt(List<JCExpression> typeArgs, JCExpression t) {
2323 if (isMode(EXPR) && token.kind == LPAREN || typeArgs != null) {
2324 selectExprMode();
2325 return arguments(typeArgs, t);
2326 } else {
2327 return t;
2328 }
2329 }
2330
2331 /** Arguments = "(" [Expression { COMMA Expression }] ")"
2332 */
2333 List<JCExpression> arguments() {
2334 ListBuffer<JCExpression> args = new ListBuffer<>();
2335 if (token.kind == LPAREN) {
2336 nextToken();
2337 if (token.kind != RPAREN) {
2338 args.append(parseExpression());
2339 while (token.kind == COMMA) {
2340 nextToken();
2341 args.append(parseExpression());
2342 }
2343 }
2344 accept(RPAREN, tk -> Errors.Expected2(RPAREN, COMMA));
2345 } else {
2346 syntaxError(token.pos, Errors.Expected(LPAREN));
2347 }
2348 return args.toList();
2349 }
2350
2351 JCExpression arguments(List<JCExpression> typeArgs, JCExpression t) {
2352 int pos = token.pos;
2353 List<JCExpression> args = arguments();
2354 JCExpression mi = F.at(pos).Apply(typeArgs, t, args);
2355 if (t.hasTag(IDENT) && isInvalidUnqualifiedMethodIdentifier(((JCIdent) t).pos,
2356 ((JCIdent) t).name)) {
2357 log.error(DiagnosticFlag.SYNTAX, t, Errors.InvalidYield);
2358 mi = F.Erroneous(List.of(mi));
2359 }
2360 return toP(mi);
2361 }
2362
2363 boolean isInvalidUnqualifiedMethodIdentifier(int pos, Name name) {
2364 if (name == names.yield) {
2365 if (allowYieldStatement) {
2366 return true;
2367 } else {
2368 log.warning(pos, Warnings.InvalidYield);
2369 }
2370 }
2371 return false;
2372 }
2373
2374 /** TypeArgumentsOpt = [ TypeArguments ]
2375 */
2376 JCExpression typeArgumentsOpt(JCExpression t) {
2377 if (token.kind == LT &&
2378 isMode(TYPE) &&
2379 !isMode(NOPARAMS)) {
2380 selectTypeMode();
2381 return typeArguments(t, false);
2382 } else {
2383 return t;
2384 }
2385 }
2386 List<JCExpression> typeArgumentsOpt() {
2387 return typeArgumentsOpt(TYPE);
2388 }
2389
2390 List<JCExpression> typeArgumentsOpt(int useMode) {
2391 if (token.kind == LT) {
2392 if (!isMode(useMode) ||
2393 isMode(NOPARAMS)) {
2394 illegal();
2395 }
2396 setMode(useMode);
2397 return typeArguments(false);
2398 }
2399 return null;
2400 }
2401
2402 /**
2403 * {@literal
2404 * TypeArguments = "<" TypeArgument {"," TypeArgument} ">"
2405 * }
2406 */
2407 List<JCExpression> typeArguments(boolean diamondAllowed) {
2408 if (token.kind == LT) {
2409 nextToken();
2410 if (token.kind == GT && diamondAllowed) {
2411 setMode(mode | DIAMOND);
2412 nextToken();
2413 return List.nil();
2414 } else {
2415 ListBuffer<JCExpression> args = new ListBuffer<>();
2416 args.append(!isMode(EXPR) ? typeArgument() : parseType());
2417 while (token.kind == COMMA) {
2418 nextToken();
2419 args.append(!isMode(EXPR) ? typeArgument() : parseType());
2420 }
2421 switch (token.kind) {
2422
2423 case GTGTGTEQ: case GTGTEQ: case GTEQ:
2424 case GTGTGT: case GTGT:
2425 token = S.split();
2426 break;
2427 case GT:
2428 nextToken();
2429 break;
2430 default:
2431 args.append(syntaxError(token.pos, Errors.Expected2(GT, COMMA)));
2432 break;
2433 }
2434 return args.toList();
2435 }
2436 } else {
2437 return List.of(syntaxError(token.pos, Errors.Expected(LT)));
2438 }
2439 }
2440
2441 /**
2442 * {@literal
2443 * TypeArgument = Type
2444 * | [Annotations] "?"
2445 * | [Annotations] "?" EXTENDS Type {"&" Type}
2446 * | [Annotations] "?" SUPER Type
2447 * }
2448 */
2449 JCExpression typeArgument() {
2450 List<JCAnnotation> annotations = typeAnnotationsOpt();
2451 if (token.kind != QUES) return parseType(false, annotations);
2452 int pos = token.pos;
2453 nextToken();
2454 JCExpression result;
2455 if (token.kind == EXTENDS) {
2456 TypeBoundKind t = to(F.at(pos).TypeBoundKind(BoundKind.EXTENDS));
2457 nextToken();
2458 JCExpression bound = parseType();
2459 result = F.at(pos).Wildcard(t, bound);
2460 } else if (token.kind == SUPER) {
2461 TypeBoundKind t = to(F.at(pos).TypeBoundKind(BoundKind.SUPER));
2462 nextToken();
2463 JCExpression bound = parseType();
2464 result = F.at(pos).Wildcard(t, bound);
2465 } else if (LAX_IDENTIFIER.test(token.kind)) {
2466 //error recovery
2467 TypeBoundKind t = F.at(Position.NOPOS).TypeBoundKind(BoundKind.UNBOUND);
2468 JCExpression wc = toP(F.at(pos).Wildcard(t, null));
2469 JCIdent id = toP(F.at(token.pos).Ident(ident()));
2470 JCErroneous err = F.at(pos).Erroneous(List.<JCTree>of(wc, id));
2471 reportSyntaxError(err, Errors.Expected3(GT, EXTENDS, SUPER));
2472 result = err;
2473 } else {
2474 TypeBoundKind t = toP(F.at(pos).TypeBoundKind(BoundKind.UNBOUND));
2475 result = toP(F.at(pos).Wildcard(t, null));
2476 }
2477 if (!annotations.isEmpty()) {
2478 result = toP(F.at(annotations.head.pos).AnnotatedType(annotations,result));
2479 }
2480 return result;
2481 }
2482
2483 JCTypeApply typeArguments(JCExpression t, boolean diamondAllowed) {
2484 int pos = token.pos;
2485 List<JCExpression> args = typeArguments(diamondAllowed);
2486 return toP(F.at(pos).TypeApply(t, args));
2487 }
2488
2489 /**
2490 * BracketsOpt = { [Annotations] "[" "]" }*
2491 *
2492 * <p>
2493 *
2494 * <code>annotations</code> is the list of annotations targeting
2495 * the expression <code>t</code>.
2496 */
2497 private JCExpression bracketsOpt(JCExpression t,
2498 List<JCAnnotation> annotations) {
2499 List<JCAnnotation> nextLevelAnnotations = typeAnnotationsOpt();
2500
2501 if (token.kind == LBRACKET) {
2502 int pos = token.pos;
2503 nextToken();
2504 t = bracketsOptCont(t, pos, nextLevelAnnotations);
2505 } else if (!nextLevelAnnotations.isEmpty()) {
2506 if (permitTypeAnnotationsPushBack) {
2507 this.typeAnnotationsPushedBack = nextLevelAnnotations;
2508 } else {
2509 return illegal(nextLevelAnnotations.head.pos);
2510 }
2511 }
2512
2513 if (!annotations.isEmpty()) {
2514 t = toP(F.at(token.pos).AnnotatedType(annotations, t));
2515 }
2516 return t;
2517 }
2518
2519 /** BracketsOpt = [ "[" "]" { [Annotations] "[" "]"} ]
2520 */
2521 private JCExpression bracketsOpt(JCExpression t) {
2522 return bracketsOpt(t, List.nil());
2523 }
2524
2525 private JCExpression bracketsOptCont(JCExpression t, int pos,
2526 List<JCAnnotation> annotations) {
2527 accept(RBRACKET);
2528 t = bracketsOpt(t);
2529 t = toP(F.at(pos).TypeArray(t));
2530 if (annotations.nonEmpty()) {
2531 t = toP(F.at(pos).AnnotatedType(annotations, t));
2532 }
2533 return t;
2534 }
2535
2536 /** BracketsSuffixExpr = "." CLASS
2537 * BracketsSuffixType =
2538 */
2539 JCExpression bracketsSuffix(JCExpression t) {
2540 if (isMode(EXPR) && token.kind == DOT) {
2541 selectExprMode();
2542 int pos = token.pos;
2543 nextToken();
2544 accept(CLASS);
2545 if (token.pos == endPosTable.errorEndPos) {
2546 // error recovery
2547 Name name;
2548 if (LAX_IDENTIFIER.test(token.kind)) {
2549 name = token.name();
2550 nextToken();
2551 } else {
2552 name = names.error;
2553 }
2554 t = F.at(pos).Erroneous(List.<JCTree>of(toP(F.at(pos).Select(t, name))));
2555 } else {
2556 Tag tag = t.getTag();
2557 // Type annotations are illegal on class literals. Annotated non array class literals
2558 // are complained about directly in term3(), Here check for type annotations on dimensions
2559 // taking care to handle some interior dimension(s) being annotated.
2560 if ((tag == TYPEARRAY && TreeInfo.containsTypeAnnotation(t)) || tag == ANNOTATED_TYPE)
2561 syntaxError(token.pos, Errors.NoAnnotationsOnDotClass);
2562 t = toP(F.at(pos).Select(t, names._class));
2563 }
2564 } else if (isMode(TYPE)) {
2565 if (token.kind != COLCOL) {
2566 selectTypeMode();
2567 }
2568 } else if (token.kind != COLCOL) {
2569 syntaxError(token.pos, Errors.DotClassExpected);
2570 }
2571 return t;
2572 }
2573
2574 /**
2575 * MemberReferenceSuffix = "::" [TypeArguments] Ident
2576 * | "::" [TypeArguments] "new"
2577 */
2578 JCExpression memberReferenceSuffix(JCExpression t) {
2579 int pos1 = token.pos;
2580 accept(COLCOL);
2581 return memberReferenceSuffix(pos1, t);
2582 }
2583
2584 JCExpression memberReferenceSuffix(int pos1, JCExpression t) {
2585 selectExprMode();
2586 List<JCExpression> typeArgs = null;
2587 if (token.kind == LT) {
2588 typeArgs = typeArguments(false);
2589 }
2590 Name refName;
2591 ReferenceMode refMode;
2592 if (token.kind == NEW) {
2593 refMode = ReferenceMode.NEW;
2594 refName = names.init;
2595 nextToken();
2596 } else {
2597 refMode = ReferenceMode.INVOKE;
2598 refName = ident();
2599 }
2600 return toP(F.at(t.getStartPosition()).Reference(refMode, refName, t, typeArgs));
2601 }
2602
2603 /** Creator = [Annotations] Qualident [TypeArguments] ( ArrayCreatorRest | ClassCreatorRest )
2604 */
2605 JCExpression creator(int newpos, List<JCExpression> typeArgs) {
2606 List<JCAnnotation> newAnnotations = typeAnnotationsOpt();
2607
2608 switch (token.kind) {
2609 case BYTE: case SHORT: case CHAR: case INT: case LONG: case FLOAT:
2610 case DOUBLE: case BOOLEAN:
2611 if (typeArgs == null) {
2612 if (newAnnotations.isEmpty()) {
2613 return arrayCreatorRest(newpos, basicType());
2614 } else {
2615 return arrayCreatorRest(newpos, toP(F.at(newAnnotations.head.pos).AnnotatedType(newAnnotations, basicType())));
2616 }
2617 }
2618 break;
2619 default:
2620 }
2621 JCExpression t = qualident(true);
2622
2623 int prevmode = mode;
2624 selectTypeMode();
2625 boolean diamondFound = false;
2626 int lastTypeargsPos = -1;
2627 if (token.kind == LT) {
2628 lastTypeargsPos = token.pos;
2629 t = typeArguments(t, true);
2630 diamondFound = isMode(DIAMOND);
2631 }
2632 while (token.kind == DOT) {
2633 if (diamondFound) {
2634 //cannot select after a diamond
2635 illegal();
2636 }
2637 int pos = token.pos;
2638 nextToken();
2639 List<JCAnnotation> tyannos = typeAnnotationsOpt();
2640 t = toP(F.at(pos).Select(t, ident()));
2641
2642 if (tyannos != null && tyannos.nonEmpty()) {
2643 t = toP(F.at(tyannos.head.pos).AnnotatedType(tyannos, t));
2644 }
2645
2646 if (token.kind == LT) {
2647 lastTypeargsPos = token.pos;
2648 t = typeArguments(t, true);
2649 diamondFound = isMode(DIAMOND);
2650 }
2651 }
2652 setMode(prevmode);
2653 if (token.kind == LBRACKET || token.kind == MONKEYS_AT) {
2654 // handle type annotations for non primitive arrays
2655 if (newAnnotations.nonEmpty()) {
2656 t = insertAnnotationsToMostInner(t, newAnnotations, false);
2657 }
2658
2659 JCExpression e = arrayCreatorRest(newpos, t);
2660 if (diamondFound) {
2661 reportSyntaxError(lastTypeargsPos, Errors.CannotCreateArrayWithDiamond);
2662 return toP(F.at(newpos).Erroneous(List.of(e)));
2663 }
2664 else if (typeArgs != null) {
2665 int pos = newpos;
2666 if (!typeArgs.isEmpty() && typeArgs.head.pos != Position.NOPOS) {
2667 // note: this should always happen but we should
2668 // not rely on this as the parser is continuously
2669 // modified to improve error recovery.
2670 pos = typeArgs.head.pos;
2671 }
2672 setErrorEndPos(S.prevToken().endPos);
2673 JCErroneous err = F.at(pos).Erroneous(typeArgs.prepend(e));
2674 reportSyntaxError(err, Errors.CannotCreateArrayWithTypeArguments);
2675 return toP(err);
2676 }
2677 return e;
2678 } else if (token.kind == LPAREN) {
2679 // handle type annotations for instantiations and anonymous classes
2680 if (newAnnotations.nonEmpty()) {
2681 t = insertAnnotationsToMostInner(t, newAnnotations, false);
2682 }
2683 return classCreatorRest(newpos, null, typeArgs, t);
2684 } else {
2685 setErrorEndPos(token.pos);
2686 reportSyntaxError(token.pos, Errors.Expected2(LPAREN, LBRACKET));
2687 t = toP(F.at(newpos).NewClass(null, typeArgs, t, List.nil(), null));
2688 return toP(F.at(newpos).Erroneous(List.<JCTree>of(t)));
2689 }
2690 }
2691
2692 /** InnerCreator = [Annotations] Ident [TypeArguments] ClassCreatorRest
2693 */
2694 JCExpression innerCreator(int newpos, List<JCExpression> typeArgs, JCExpression encl) {
2695 List<JCAnnotation> newAnnotations = typeAnnotationsOpt();
2696
2697 JCExpression t = toP(F.at(token.pos).Ident(ident()));
2698
2699 if (newAnnotations.nonEmpty()) {
2700 t = toP(F.at(newAnnotations.head.pos).AnnotatedType(newAnnotations, t));
2701 }
2702
2703 if (token.kind == LT) {
2704 int prevmode = mode;
2705 t = typeArguments(t, true);
2706 setMode(prevmode);
2707 }
2708 return classCreatorRest(newpos, encl, typeArgs, t);
2709 }
2710
2711 /** ArrayCreatorRest = [Annotations] "[" ( "]" BracketsOpt ArrayInitializer
2712 * | Expression "]" {[Annotations] "[" Expression "]"} BracketsOpt )
2713 */
2714 JCExpression arrayCreatorRest(int newpos, JCExpression elemtype) {
2715 List<JCAnnotation> annos = typeAnnotationsOpt();
2716
2717 accept(LBRACKET);
2718 if (token.kind == RBRACKET) {
2719 accept(RBRACKET);
2720 elemtype = bracketsOpt(elemtype, annos);
2721 if (token.kind == LBRACE) {
2722 JCNewArray na = (JCNewArray)arrayInitializer(newpos, elemtype);
2723 if (annos.nonEmpty()) {
2724 // when an array initializer is present then
2725 // the parsed annotations should target the
2726 // new array tree
2727 // bracketsOpt inserts the annotation in
2728 // elemtype, and it needs to be corrected
2729 //
2730 JCAnnotatedType annotated = (JCAnnotatedType)elemtype;
2731 assert annotated.annotations == annos;
2732 na.annotations = annotated.annotations;
2733 na.elemtype = annotated.underlyingType;
2734 }
2735 return na;
2736 } else {
2737 JCExpression t = toP(F.at(newpos).NewArray(elemtype, List.nil(), null));
2738 return syntaxError(token.pos, List.of(t), Errors.ArrayDimensionMissing);
2739 }
2740 } else {
2741 ListBuffer<JCExpression> dims = new ListBuffer<>();
2742
2743 // maintain array dimension type annotations
2744 ListBuffer<List<JCAnnotation>> dimAnnotations = new ListBuffer<>();
2745 dimAnnotations.append(annos);
2746
2747 dims.append(parseExpression());
2748 accept(RBRACKET);
2749 while (token.kind == LBRACKET
2750 || token.kind == MONKEYS_AT) {
2751 List<JCAnnotation> maybeDimAnnos = typeAnnotationsOpt();
2752 int pos = token.pos;
2753 nextToken();
2754 if (token.kind == RBRACKET) { // no dimension
2755 elemtype = bracketsOptCont(elemtype, pos, maybeDimAnnos);
2756 } else {
2757 dimAnnotations.append(maybeDimAnnos);
2758 dims.append(parseExpression());
2759 accept(RBRACKET);
2760 }
2761 }
2762
2763 List<JCExpression> elems = null;
2764 int errpos = token.pos;
2765
2766 if (token.kind == LBRACE) {
2767 elems = arrayInitializerElements(newpos, elemtype);
2768 }
2769
2770 JCNewArray na = toP(F.at(newpos).NewArray(elemtype, dims.toList(), elems));
2771 na.dimAnnotations = dimAnnotations.toList();
2772
2773 if (elems != null) {
2774 return syntaxError(errpos, List.of(na), Errors.IllegalArrayCreationBothDimensionAndInitialization);
2775 }
2776
2777 return na;
2778 }
2779 }
2780
2781 /** ClassCreatorRest = Arguments [ClassBody]
2782 */
2783 JCNewClass classCreatorRest(int newpos,
2784 JCExpression encl,
2785 List<JCExpression> typeArgs,
2786 JCExpression t)
2787 {
2788 List<JCExpression> args = arguments();
2789 JCClassDecl body = null;
2790 if (token.kind == LBRACE) {
2791 ignoreDanglingComments(); // ignore any comments from before the '{'
2792 int pos = token.pos;
2793 List<JCTree> defs = classInterfaceOrRecordBody(names.empty, false, false);
2794 JCModifiers mods = F.at(Position.NOPOS).Modifiers(0);
2795 body = toP(F.at(pos).AnonymousClassDef(mods, defs));
2796 }
2797 return toP(F.at(newpos).NewClass(encl, typeArgs, t, args, body));
2798 }
2799
2800 /** ArrayInitializer = "{" [VariableInitializer {"," VariableInitializer}] [","] "}"
2801 */
2802 JCExpression arrayInitializer(int newpos, JCExpression t) {
2803 List<JCExpression> elems = arrayInitializerElements(newpos, t);
2804 return toP(F.at(newpos).NewArray(t, List.nil(), elems));
2805 }
2806
2807 List<JCExpression> arrayInitializerElements(int newpos, JCExpression t) {
2808 accept(LBRACE);
2809 ListBuffer<JCExpression> elems = new ListBuffer<>();
2810 if (token.kind == COMMA) {
2811 nextToken();
2812 } else if (token.kind != RBRACE) {
2813 elems.append(variableInitializer());
2814 while (token.kind == COMMA) {
2815 nextToken();
2816 if (token.kind == RBRACE) break;
2817 elems.append(variableInitializer());
2818 }
2819 }
2820 accept(RBRACE);
2821 return elems.toList();
2822 }
2823
2824 /** VariableInitializer = ArrayInitializer | Expression
2825 */
2826 public JCExpression variableInitializer() {
2827 return token.kind == LBRACE ? arrayInitializer(token.pos, null) : parseExpression();
2828 }
2829
2830 /** ParExpression = "(" Expression ")"
2831 */
2832 JCExpression parExpression() {
2833 int pos = token.pos;
2834 accept(LPAREN);
2835 JCExpression t = parseExpression();
2836 accept(RPAREN);
2837 return toP(F.at(pos).Parens(t));
2838 }
2839
2840 /** Block = "{" BlockStatements "}"
2841 */
2842 JCBlock block(int pos, long flags) {
2843 accept(LBRACE);
2844 ignoreDanglingComments(); // ignore any comments from before the '{'
2845 List<JCStatement> stats = blockStatements();
2846 JCBlock t = F.at(pos).Block(flags, stats);
2847 while (token.kind == CASE || token.kind == DEFAULT) {
2848 syntaxError(token.pos, Errors.Orphaned(token.kind));
2849 switchBlockStatementGroups();
2850 }
2851 // the Block node has a field "bracePos" for first char of last token, which is
2852 // usually but not necessarily the last char of the last token.
2853 t.bracePos = token.pos;
2854 accept(RBRACE);
2855 return toP(t);
2856 }
2857
2858 public JCBlock block() {
2859 return block(token.pos, 0);
2860 }
2861
2862 /** BlockStatements = { BlockStatement }
2863 * BlockStatement = LocalVariableDeclarationStatement
2864 * | ClassOrInterfaceOrEnumDeclaration
2865 * | [Ident ":"] Statement
2866 * LocalVariableDeclarationStatement
2867 * = { FINAL | '@' Annotation } Type VariableDeclarators ";"
2868 */
2869 List<JCStatement> blockStatements() {
2870 //todo: skip to anchor on error(?)
2871 int lastErrPos = -1;
2872 ListBuffer<JCStatement> stats = new ListBuffer<>();
2873 while (true) {
2874 List<JCStatement> stat = blockStatement();
2875 ignoreDanglingComments(); // ignore comments not consumed by the statement
2876 if (stat.isEmpty()) {
2877 return stats.toList();
2878 } else {
2879 // error recovery
2880 if (token.pos == lastErrPos)
2881 return stats.toList();
2882 if (token.pos <= endPosTable.errorEndPos) {
2883 skip(false, true, true, true);
2884 lastErrPos = token.pos;
2885 }
2886 stats.addAll(stat);
2887 }
2888 }
2889 }
2890
2891 /*
2892 * Parse a Statement (JLS 14.5). As an enhancement to improve error recovery,
2893 * this method will also recognize variable and class declarations (which are
2894 * not legal for a Statement) by delegating the parsing to BlockStatement (JLS 14.2).
2895 * If any illegal declarations are found, they will be wrapped in an erroneous tree,
2896 * and an error will be produced by this method.
2897 */
2898 JCStatement parseStatementAsBlock() {
2899 int pos = token.pos;
2900 List<JCStatement> stats = blockStatement();
2901 if (stats.isEmpty()) {
2902 JCErroneous e = syntaxError(pos, Errors.IllegalStartOfStmt);
2903 return toP(F.at(pos).Exec(e));
2904 } else {
2905 JCStatement first = stats.head;
2906 Error error = null;
2907 switch (first.getTag()) {
2908 case CLASSDEF:
2909 error = Errors.ClassNotAllowed;
2910 break;
2911 case VARDEF:
2912 error = Errors.VariableNotAllowed;
2913 break;
2914 }
2915 if (error != null) {
2916 log.error(DiagnosticFlag.SYNTAX, first, error);
2917 List<JCBlock> blist = List.of(F.at(first.pos).Block(0, stats));
2918 return toP(F.at(pos).Exec(F.at(first.pos).Erroneous(blist)));
2919 }
2920 return first;
2921 }
2922 }
2923
2924 /**This method parses a statement appearing inside a block.
2925 */
2926 List<JCStatement> blockStatement() {
2927 //todo: skip to anchor on error(?)
2928 Comment dc;
2929 int pos = token.pos;
2930 switch (token.kind) {
2931 case RBRACE: case CASE: case DEFAULT: case EOF:
2932 return List.nil();
2933 case LBRACE: case IF: case FOR: case WHILE: case DO: case TRY:
2934 case SWITCH: case SYNCHRONIZED: case RETURN: case THROW: case BREAK:
2935 case CONTINUE: case SEMI: case ELSE: case FINALLY: case CATCH:
2936 case ASSERT:
2937 return List.of(parseSimpleStatement());
2938 case MONKEYS_AT:
2939 case FINAL: {
2940 dc = token.docComment();
2941 JCModifiers mods = modifiersOpt();
2942 if (isDeclaration()) {
2943 return List.of(classOrRecordOrInterfaceOrEnumDeclaration(mods, dc));
2944 } else {
2945 JCExpression t = parseType(true);
2946 return localVariableDeclarations(mods, t, dc);
2947 }
2948 }
2949 case ABSTRACT: case STRICTFP: {
2950 dc = token.docComment();
2951 JCModifiers mods = modifiersOpt();
2952 return List.of(classOrRecordOrInterfaceOrEnumDeclaration(mods, dc));
2953 }
2954 case INTERFACE:
2955 case CLASS:
2956 dc = token.docComment();
2957 return List.of(classOrRecordOrInterfaceOrEnumDeclaration(modifiersOpt(), dc));
2958 case ENUM:
2959 if (!allowRecords) {
2960 log.error(DiagnosticFlag.SYNTAX, token.pos, Errors.LocalEnum);
2961 }
2962 dc = token.docComment();
2963 return List.of(classOrRecordOrInterfaceOrEnumDeclaration(modifiersOpt(), dc));
2964 case IDENTIFIER:
2965 if (token.name() == names.yield && allowYieldStatement) {
2966 Token next = S.token(1);
2967 boolean isYieldStatement;
2968 switch (next.kind) {
2969 case PLUS: case SUB: case STRINGLITERAL: case CHARLITERAL:
2970 case STRINGFRAGMENT:
2971 case INTLITERAL: case LONGLITERAL: case FLOATLITERAL: case DOUBLELITERAL:
2972 case NULL: case IDENTIFIER: case UNDERSCORE: case TRUE: case FALSE:
2973 case NEW: case SWITCH: case THIS: case SUPER:
2974 case BYTE, CHAR, SHORT, INT, LONG, FLOAT, DOUBLE, VOID, BOOLEAN:
2975 isYieldStatement = true;
2976 break;
2977 case PLUSPLUS: case SUBSUB:
2978 isYieldStatement = S.token(2).kind != SEMI;
2979 break;
2980 case BANG: case TILDE:
2981 isYieldStatement = S.token(1).kind != SEMI;
2982 break;
2983 case LPAREN:
2984 int lookahead = 2;
2985 int balance = 1;
2986 boolean hasComma = false;
2987 boolean inTypeArgs = false;
2988 Token l;
2989 while ((l = S.token(lookahead)).kind != EOF && balance != 0) {
2990 switch (l.kind) {
2991 case LPAREN: balance++; break;
2992 case RPAREN: balance--; break;
2993 case COMMA: if (balance == 1 && !inTypeArgs) hasComma = true; break;
2994 case LT: inTypeArgs = true; break;
2995 case GT: inTypeArgs = false;
2996 }
2997 lookahead++;
2998 }
2999 isYieldStatement = (!hasComma && lookahead != 3) || l.kind == ARROW;
3000 break;
3001 case SEMI: //error recovery - this is not a valid statement:
3002 isYieldStatement = true;
3003 break;
3004 default:
3005 isYieldStatement = false;
3006 break;
3007 }
3008
3009 if (isYieldStatement) {
3010 nextToken();
3011 JCExpression t = term(EXPR);
3012 accept(SEMI);
3013 return List.of(toP(F.at(pos).Yield(t)));
3014 }
3015
3016 //else intentional fall-through
3017 } else {
3018 if (isNonSealedClassStart(true)) {
3019 log.error(token.pos, Errors.SealedOrNonSealedLocalClassesNotAllowed);
3020 nextToken();
3021 nextToken();
3022 nextToken();
3023 return List.of(classOrRecordOrInterfaceOrEnumDeclaration(modifiersOpt(), token.docComment()));
3024 } else if (isSealedClassStart(true)) {
3025 checkSourceLevel(Feature.SEALED_CLASSES);
3026 log.error(token.pos, Errors.SealedOrNonSealedLocalClassesNotAllowed);
3027 nextToken();
3028 return List.of(classOrRecordOrInterfaceOrEnumDeclaration(modifiersOpt(), token.docComment()));
3029 }
3030 }
3031 }
3032 dc = token.docComment();
3033 if (isRecordStart() && allowRecords) {
3034 return List.of(recordDeclaration(F.at(pos).Modifiers(0), dc));
3035 } else {
3036 Token prevToken = token;
3037 JCExpression t = term(EXPR | TYPE);
3038 if (token.kind == COLON && t.hasTag(IDENT)) {
3039 nextToken();
3040 JCStatement stat = parseStatementAsBlock();
3041 return List.of(F.at(pos).Labelled(prevToken.name(), stat));
3042 } else if (wasTypeMode() && LAX_IDENTIFIER.test(token.kind)) {
3043 pos = token.pos;
3044 JCModifiers mods = F.at(Position.NOPOS).Modifiers(0);
3045 F.at(pos);
3046 return localVariableDeclarations(mods, t, dc);
3047 } else {
3048 // This Exec is an "ExpressionStatement"; it subsumes the terminating semicolon
3049 t = checkExprStat(t);
3050 accept(SEMI);
3051 JCExpressionStatement expr = toP(F.at(pos).Exec(t));
3052 return List.of(expr);
3053 }
3054 }
3055 }
3056 //where
3057 private List<JCStatement> localVariableDeclarations(JCModifiers mods, JCExpression type, Comment dc) {
3058 if (dc != null) {
3059 // ignore a well-placed doc comment, but save any misplaced ones
3060 saveDanglingDocComments(dc);
3061 }
3062 ListBuffer<JCStatement> stats =
3063 variableDeclarators(mods, type, new ListBuffer<>(), true);
3064 // A "LocalVariableDeclarationStatement" subsumes the terminating semicolon
3065 accept(SEMI);
3066 storeEnd(stats.last(), S.prevToken().endPos);
3067 return stats.toList();
3068 }
3069
3070 /** Statement =
3071 * Block
3072 * | IF ParExpression Statement [ELSE Statement]
3073 * | FOR "(" ForInitOpt ";" [Expression] ";" ForUpdateOpt ")" Statement
3074 * | FOR "(" FormalParameter : Expression ")" Statement
3075 * | WHILE ParExpression Statement
3076 * | DO Statement WHILE ParExpression ";"
3077 * | TRY Block ( Catches | [Catches] FinallyPart )
3078 * | TRY "(" ResourceSpecification ";"opt ")" Block [Catches] [FinallyPart]
3079 * | SWITCH ParExpression "{" SwitchBlockStatementGroups "}"
3080 * | SYNCHRONIZED ParExpression Block
3081 * | RETURN [Expression] ";"
3082 * | THROW Expression ";"
3083 * | BREAK [Ident] ";"
3084 * | CONTINUE [Ident] ";"
3085 * | ASSERT Expression [ ":" Expression ] ";"
3086 * | ";"
3087 */
3088 public JCStatement parseSimpleStatement() {
3089 ignoreDanglingComments(); // ignore comments before statement
3090 int pos = token.pos;
3091 switch (token.kind) {
3092 case LBRACE:
3093 return block();
3094 case IF: {
3095 nextToken();
3096 JCExpression cond = parExpression();
3097 JCStatement thenpart = parseStatementAsBlock();
3098 JCStatement elsepart = null;
3099 if (token.kind == ELSE) {
3100 nextToken();
3101 elsepart = parseStatementAsBlock();
3102 }
3103 return F.at(pos).If(cond, thenpart, elsepart);
3104 }
3105 case FOR: {
3106 nextToken();
3107 accept(LPAREN);
3108 List<JCStatement> inits = token.kind == SEMI ? List.nil() : forInit();
3109 if (inits.length() == 1 &&
3110 inits.head.hasTag(VARDEF) &&
3111 ((JCVariableDecl) inits.head).init == null &&
3112 token.kind == COLON) {
3113 JCVariableDecl var = (JCVariableDecl)inits.head;
3114 accept(COLON);
3115 JCExpression expr = parseExpression();
3116 accept(RPAREN);
3117 JCStatement body = parseStatementAsBlock();
3118 return F.at(pos).ForeachLoop(var, expr, body);
3119 } else {
3120 accept(SEMI);
3121 JCExpression cond = token.kind == SEMI ? null : parseExpression();
3122 accept(SEMI);
3123 List<JCExpressionStatement> steps = token.kind == RPAREN ? List.nil() : forUpdate();
3124 accept(RPAREN);
3125 JCStatement body = parseStatementAsBlock();
3126 return F.at(pos).ForLoop(inits, cond, steps, body);
3127 }
3128 }
3129 case WHILE: {
3130 nextToken();
3131 JCExpression cond = parExpression();
3132 JCStatement body = parseStatementAsBlock();
3133 return F.at(pos).WhileLoop(cond, body);
3134 }
3135 case DO: {
3136 nextToken();
3137 JCStatement body = parseStatementAsBlock();
3138 accept(WHILE);
3139 JCExpression cond = parExpression();
3140 accept(SEMI);
3141 JCDoWhileLoop t = toP(F.at(pos).DoLoop(body, cond));
3142 return t;
3143 }
3144 case TRY: {
3145 nextToken();
3146 List<JCTree> resources = List.nil();
3147 if (token.kind == LPAREN) {
3148 nextToken();
3149 resources = resources();
3150 accept(RPAREN);
3151 }
3152 JCBlock body = block();
3153 ListBuffer<JCCatch> catchers = new ListBuffer<>();
3154 JCBlock finalizer = null;
3155 if (token.kind == CATCH || token.kind == FINALLY) {
3156 while (token.kind == CATCH) catchers.append(catchClause());
3157 if (token.kind == FINALLY) {
3158 nextToken();
3159 finalizer = block();
3160 }
3161 } else {
3162 if (resources.isEmpty()) {
3163 log.error(DiagnosticFlag.SYNTAX, pos, Errors.TryWithoutCatchFinallyOrResourceDecls);
3164 }
3165 }
3166 return F.at(pos).Try(resources, body, catchers.toList(), finalizer);
3167 }
3168 case SWITCH: {
3169 nextToken();
3170 JCExpression selector = parExpression();
3171 accept(LBRACE);
3172 List<JCCase> cases = switchBlockStatementGroups();
3173 JCSwitch t = to(F.at(pos).Switch(selector, cases));
3174 t.bracePos = token.endPos;
3175 accept(RBRACE);
3176 return t;
3177 }
3178 case SYNCHRONIZED: {
3179 nextToken();
3180 JCExpression lock = parExpression();
3181 JCBlock body = block();
3182 return F.at(pos).Synchronized(lock, body);
3183 }
3184 case RETURN: {
3185 nextToken();
3186 JCExpression result = token.kind == SEMI ? null : parseExpression();
3187 accept(SEMI);
3188 JCReturn t = toP(F.at(pos).Return(result));
3189 return t;
3190 }
3191 case THROW: {
3192 nextToken();
3193 JCExpression exc = parseExpression();
3194 accept(SEMI);
3195 JCThrow t = toP(F.at(pos).Throw(exc));
3196 return t;
3197 }
3198 case BREAK: {
3199 nextToken();
3200 Name label = LAX_IDENTIFIER.test(token.kind) ? ident() : null;
3201 accept(SEMI);
3202 JCBreak t = toP(F.at(pos).Break(label));
3203 return t;
3204 }
3205 case CONTINUE: {
3206 nextToken();
3207 Name label = LAX_IDENTIFIER.test(token.kind) ? ident() : null;
3208 accept(SEMI);
3209 JCContinue t = toP(F.at(pos).Continue(label));
3210 return t;
3211 }
3212 case SEMI:
3213 nextToken();
3214 return toP(F.at(pos).Skip());
3215 case ELSE:
3216 int elsePos = token.pos;
3217 nextToken();
3218 return doRecover(elsePos, BasicErrorRecoveryAction.BLOCK_STMT, Errors.ElseWithoutIf);
3219 case FINALLY:
3220 int finallyPos = token.pos;
3221 nextToken();
3222 return doRecover(finallyPos, BasicErrorRecoveryAction.BLOCK_STMT, Errors.FinallyWithoutTry);
3223 case CATCH:
3224 return doRecover(token.pos, BasicErrorRecoveryAction.CATCH_CLAUSE, Errors.CatchWithoutTry);
3225 case ASSERT: {
3226 nextToken();
3227 JCExpression assertion = parseExpression();
3228 JCExpression message = null;
3229 if (token.kind == COLON) {
3230 nextToken();
3231 message = parseExpression();
3232 }
3233 accept(SEMI);
3234 JCAssert t = toP(F.at(pos).Assert(assertion, message));
3235 return t;
3236 }
3237 default:
3238 Assert.error();
3239 return null;
3240 }
3241 }
3242
3243 @Override
3244 public JCStatement parseStatement() {
3245 return parseStatementAsBlock();
3246 }
3247
3248 private JCStatement doRecover(int startPos, ErrorRecoveryAction action, Error errorKey) {
3249 int errPos = S.errPos();
3250 JCTree stm = action.doRecover(this);
3251 S.errPos(errPos);
3252 return toP(F.Exec(syntaxError(startPos, List.of(stm), errorKey)));
3253 }
3254
3255 /** CatchClause = CATCH "(" FormalParameter ")" Block
3256 * TODO: the "FormalParameter" is not correct, it uses the special "catchTypes" rule below.
3257 */
3258 protected JCCatch catchClause() {
3259 int pos = token.pos;
3260 accept(CATCH);
3261 accept(LPAREN);
3262 JCModifiers mods = optFinal(Flags.PARAMETER);
3263 List<JCExpression> catchTypes = catchTypes();
3264 JCExpression paramType = catchTypes.size() > 1 ?
3265 toP(F.at(catchTypes.head.getStartPosition()).TypeUnion(catchTypes)) :
3266 catchTypes.head;
3267 JCVariableDecl formal = variableDeclaratorId(mods, paramType, true, false, false);
3268 accept(RPAREN);
3269 JCBlock body = block();
3270 return F.at(pos).Catch(formal, body);
3271 }
3272
3273 List<JCExpression> catchTypes() {
3274 ListBuffer<JCExpression> catchTypes = new ListBuffer<>();
3275 catchTypes.add(parseType());
3276 while (token.kind == BAR) {
3277 nextToken();
3278 // Instead of qualident this is now parseType.
3279 // But would that allow too much, e.g. arrays or generics?
3280 catchTypes.add(parseType());
3281 }
3282 return catchTypes.toList();
3283 }
3284
3285 /** SwitchBlockStatementGroups = { SwitchBlockStatementGroup }
3286 * SwitchBlockStatementGroup = SwitchLabel BlockStatements
3287 * SwitchLabel = CASE ConstantExpression ":" | DEFAULT ":"
3288 */
3289 List<JCCase> switchBlockStatementGroups() {
3290 ListBuffer<JCCase> cases = new ListBuffer<>();
3291 while (true) {
3292 int pos = token.pos;
3293 switch (token.kind) {
3294 case CASE:
3295 case DEFAULT:
3296 cases.appendList(switchBlockStatementGroup());
3297 break;
3298 case RBRACE: case EOF:
3299 return cases.toList();
3300 default:
3301 nextToken(); // to ensure progress
3302 syntaxError(pos, Errors.Expected3(CASE, DEFAULT, RBRACE));
3303 }
3304 }
3305 }
3306
3307 protected List<JCCase> switchBlockStatementGroup() {
3308 int pos = token.pos;
3309 List<JCStatement> stats;
3310 JCCase c;
3311 ListBuffer<JCCase> cases = new ListBuffer<JCCase>();
3312 switch (token.kind) {
3313 case CASE: {
3314 nextToken();
3315 ListBuffer<JCCaseLabel> pats = new ListBuffer<>();
3316 boolean allowDefault = false;
3317 while (true) {
3318 JCCaseLabel label = parseCaseLabel(allowDefault);
3319 pats.append(label);
3320 if (token.kind != COMMA) break;
3321 nextToken();
3322 checkSourceLevel(Feature.SWITCH_MULTIPLE_CASE_LABELS);
3323 allowDefault = TreeInfo.isNullCaseLabel(label);
3324 };
3325 JCExpression guard = parseGuard(pats.last());
3326 CaseTree.CaseKind caseKind;
3327 JCTree body = null;
3328 if (token.kind == ARROW) {
3329 checkSourceLevel(Feature.SWITCH_RULE);
3330 accept(ARROW);
3331 caseKind = JCCase.RULE;
3332 JCStatement statement = parseStatementAsBlock();
3333 if (!statement.hasTag(EXEC) && !statement.hasTag(BLOCK) && !statement.hasTag(Tag.THROW)) {
3334 log.error(statement.pos(), Errors.SwitchCaseUnexpectedStatement);
3335 }
3336 stats = List.of(statement);
3337 body = stats.head;
3338 } else {
3339 accept(COLON, tk -> Errors.Expected2(COLON, ARROW));
3340 caseKind = JCCase.STATEMENT;
3341 stats = blockStatements();
3342 }
3343 c = F.at(pos).Case(caseKind, pats.toList(), guard, stats, body);
3344 if (stats.isEmpty())
3345 storeEnd(c, S.prevToken().endPos);
3346 return cases.append(c).toList();
3347 }
3348 case DEFAULT: {
3349 nextToken();
3350 JCCaseLabel defaultPattern = toP(F.at(pos).DefaultCaseLabel());
3351 JCExpression guard = parseGuard(defaultPattern);
3352 CaseTree.CaseKind caseKind;
3353 JCTree body = null;
3354 if (token.kind == ARROW) {
3355 checkSourceLevel(Feature.SWITCH_RULE);
3356 accept(ARROW);
3357 caseKind = JCCase.RULE;
3358 JCStatement statement = parseStatementAsBlock();
3359 if (!statement.hasTag(EXEC) && !statement.hasTag(BLOCK) && !statement.hasTag(Tag.THROW)) {
3360 log.error(statement.pos(), Errors.SwitchCaseUnexpectedStatement);
3361 }
3362 stats = List.of(statement);
3363 body = stats.head;
3364 } else {
3365 accept(COLON, tk -> Errors.Expected2(COLON, ARROW));
3366 caseKind = JCCase.STATEMENT;
3367 stats = blockStatements();
3368 }
3369 c = F.at(pos).Case(caseKind, List.of(defaultPattern), guard, stats, body);
3370 if (stats.isEmpty())
3371 storeEnd(c, S.prevToken().endPos);
3372 return cases.append(c).toList();
3373 }
3374 }
3375 throw new AssertionError("should not reach here");
3376 }
3377
3378 private JCCaseLabel parseCaseLabel(boolean allowDefault) {
3379 int patternPos = token.pos;
3380 JCCaseLabel label;
3381
3382 if (token.kind == DEFAULT) {
3383 checkSourceLevel(token.pos, Feature.PATTERN_SWITCH);
3384 if (!allowDefault) {
3385 reportSyntaxError(new SimpleDiagnosticPosition(token.pos),
3386 Errors.DefaultLabelNotAllowed);
3387 }
3388 nextToken();
3389 label = toP(F.at(patternPos).DefaultCaseLabel());
3390 } else {
3391 JCModifiers mods = optFinal(0);
3392 boolean pattern = mods.flags != 0 || mods.annotations.nonEmpty() ||
3393 analyzePattern(0) == PatternResult.PATTERN;
3394 if (pattern) {
3395 checkSourceLevel(token.pos, Feature.PATTERN_SWITCH);
3396 JCPattern p = parsePattern(patternPos, mods, null, false, true);
3397 return toP(F.at(patternPos).PatternCaseLabel(p));
3398 } else {
3399 JCExpression expr = term(EXPR | NOLAMBDA);
3400 return toP(F.at(patternPos).ConstantCaseLabel(expr));
3401 }
3402 }
3403
3404 return label;
3405 }
3406
3407 private JCExpression parseGuard(JCCaseLabel label) {
3408 JCExpression guard = null;
3409
3410 if (token.kind == IDENTIFIER && token.name() == names.when) {
3411 int pos = token.pos;
3412
3413 nextToken();
3414 guard = term(EXPR | NOLAMBDA);
3415
3416 if (!(label instanceof JCPatternCaseLabel)) {
3417 guard = syntaxError(pos, List.of(guard), Errors.GuardNotAllowed);
3418 }
3419 }
3420
3421 return guard;
3422 }
3423 @SuppressWarnings("fallthrough")
3424 PatternResult analyzePattern(int lookahead) {
3425 int typeDepth = 0;
3426 int parenDepth = 0;
3427 PatternResult pendingResult = PatternResult.EXPRESSION;
3428 while (true) {
3429 TokenKind token = S.token(lookahead).kind;
3430 switch (token) {
3431 case BYTE: case SHORT: case INT: case LONG: case FLOAT:
3432 case DOUBLE: case BOOLEAN: case CHAR: case VOID:
3433 case ASSERT, ENUM, IDENTIFIER:
3434 if (typeDepth == 0 && peekToken(lookahead, LAX_IDENTIFIER)) {
3435 if (parenDepth == 0) {
3436 return PatternResult.PATTERN;
3437 } else {
3438 pendingResult = PatternResult.PATTERN;
3439 }
3440 } else if (typeDepth == 0 && parenDepth == 0 && (peekToken(lookahead, tk -> tk == ARROW || tk == COMMA))) {
3441 return PatternResult.EXPRESSION;
3442 }
3443 break;
3444 case UNDERSCORE:
3445 // TODO: REFACTOR to remove the code duplication
3446 if (typeDepth == 0 && peekToken(lookahead, tk -> tk == RPAREN || tk == COMMA)) {
3447 return PatternResult.PATTERN;
3448 } else if (typeDepth == 0 && peekToken(lookahead, LAX_IDENTIFIER)) {
3449 if (parenDepth == 0) {
3450 return PatternResult.PATTERN;
3451 } else {
3452 pendingResult = PatternResult.PATTERN;
3453 }
3454 }
3455 break;
3456 case DOT, QUES, EXTENDS, SUPER, COMMA: break;
3457 case LT: typeDepth++; break;
3458 case GTGTGT: typeDepth--;
3459 case GTGT: typeDepth--;
3460 case GT:
3461 typeDepth--;
3462 if (typeDepth == 0 && !peekToken(lookahead, DOT)) {
3463 return peekToken(lookahead, LAX_IDENTIFIER) ||
3464 peekToken(lookahead, tk -> tk == LPAREN) ? PatternResult.PATTERN
3465 : PatternResult.EXPRESSION;
3466 } else if (typeDepth < 0) return PatternResult.EXPRESSION;
3467 break;
3468 case MONKEYS_AT:
3469 lookahead = skipAnnotation(lookahead);
3470 break;
3471 case LBRACKET:
3472 if (peekToken(lookahead, RBRACKET, LAX_IDENTIFIER)) {
3473 return PatternResult.PATTERN;
3474 } else if (peekToken(lookahead, RBRACKET)) {
3475 lookahead++;
3476 break;
3477 } else {
3478 // This is a potential guard, if we are already in a pattern
3479 return pendingResult;
3480 }
3481 case LPAREN:
3482 if (S.token(lookahead + 1).kind == RPAREN) {
3483 return parenDepth != 0 && S.token(lookahead + 2).kind == ARROW
3484 ? PatternResult.EXPRESSION
3485 : PatternResult.PATTERN;
3486 }
3487 parenDepth++; break;
3488 case RPAREN:
3489 parenDepth--;
3490 if (parenDepth == 0 &&
3491 typeDepth == 0 &&
3492 peekToken(lookahead, TokenKind.IDENTIFIER) &&
3493 S.token(lookahead + 1).name() == names.when) {
3494 return PatternResult.PATTERN;
3495 }
3496 break;
3497 case ARROW: return parenDepth > 0 ? PatternResult.EXPRESSION
3498 : pendingResult;
3499 case FINAL:
3500 if (parenDepth > 0) return PatternResult.PATTERN;
3501 default: return pendingResult;
3502 }
3503 lookahead++;
3504 }
3505 }
3506
3507 private enum PatternResult {
3508 EXPRESSION,
3509 PATTERN;
3510 }
3511
3512 /** MoreStatementExpressions = { COMMA StatementExpression }
3513 */
3514 <T extends ListBuffer<? super JCExpressionStatement>> T moreStatementExpressions(int pos,
3515 JCExpression first,
3516 T stats) {
3517 // This Exec is a "StatementExpression"; it subsumes no terminating token
3518 stats.append(toP(F.at(pos).Exec(checkExprStat(first))));
3519 while (token.kind == COMMA) {
3520 nextToken();
3521 pos = token.pos;
3522 JCExpression t = parseExpression();
3523 // This Exec is a "StatementExpression"; it subsumes no terminating token
3524 stats.append(toP(F.at(pos).Exec(checkExprStat(t))));
3525 }
3526 return stats;
3527 }
3528
3529 /** ForInit = StatementExpression MoreStatementExpressions
3530 * | { FINAL | '@' Annotation } Type VariableDeclarators
3531 */
3532 List<JCStatement> forInit() {
3533 ListBuffer<JCStatement> stats = new ListBuffer<>();
3534 int pos = token.pos;
3535 if (token.kind == FINAL || token.kind == MONKEYS_AT) {
3536 return variableDeclarators(optFinal(0), parseType(true), stats, true).toList();
3537 } else {
3538 JCExpression t = term(EXPR | TYPE);
3539 if (wasTypeMode() && LAX_IDENTIFIER.test(token.kind)) {
3540 return variableDeclarators(modifiersOpt(), t, stats, true).toList();
3541 } else if (wasTypeMode() && token.kind == COLON) {
3542 log.error(DiagnosticFlag.SYNTAX, pos, Errors.BadInitializer("for-loop"));
3543 return List.of((JCStatement)F.at(pos).VarDef(modifiersOpt(), names.error, t, null));
3544 } else {
3545 return moreStatementExpressions(pos, t, stats).toList();
3546 }
3547 }
3548 }
3549
3550 /** ForUpdate = StatementExpression MoreStatementExpressions
3551 */
3552 List<JCExpressionStatement> forUpdate() {
3553 return moreStatementExpressions(token.pos,
3554 parseExpression(),
3555 new ListBuffer<JCExpressionStatement>()).toList();
3556 }
3557
3558 /** AnnotationsOpt = { '@' Annotation }
3559 *
3560 * @param kind Whether to parse an ANNOTATION or TYPE_ANNOTATION
3561 */
3562 protected List<JCAnnotation> annotationsOpt(Tag kind) {
3563 if (token.kind != MONKEYS_AT) return List.nil(); // optimization
3564 ListBuffer<JCAnnotation> buf = new ListBuffer<>();
3565 int prevmode = mode;
3566 while (token.kind == MONKEYS_AT) {
3567 int pos = token.pos;
3568 nextToken();
3569 buf.append(annotation(pos, kind));
3570 }
3571 setLastMode(mode);
3572 setMode(prevmode);
3573 List<JCAnnotation> annotations = buf.toList();
3574
3575 return annotations;
3576 }
3577
3578 List<JCAnnotation> typeAnnotationsOpt() {
3579 List<JCAnnotation> annotations = annotationsOpt(Tag.TYPE_ANNOTATION);
3580 return annotations;
3581 }
3582
3583 /** ModifiersOpt = { Modifier }
3584 * Modifier = PUBLIC | PROTECTED | PRIVATE | STATIC | ABSTRACT | FINAL
3585 * | NATIVE | SYNCHRONIZED | TRANSIENT | VOLATILE | "@"
3586 * | "@" Annotation
3587 */
3588 protected JCModifiers modifiersOpt() {
3589 return modifiersOpt(null);
3590 }
3591 protected JCModifiers modifiersOpt(JCModifiers partial) {
3592 long flags;
3593 ListBuffer<JCAnnotation> annotations = new ListBuffer<>();
3594 int pos;
3595 if (partial == null) {
3596 flags = 0;
3597 pos = token.pos;
3598 } else {
3599 flags = partial.flags;
3600 annotations.appendList(partial.annotations);
3601 pos = partial.pos;
3602 }
3603 if (token.deprecatedFlag()) {
3604 flags |= Flags.DEPRECATED;
3605 }
3606 int lastPos;
3607 loop:
3608 while (true) {
3609 long flag;
3610 switch (token.kind) {
3611 case PRIVATE : flag = Flags.PRIVATE; break;
3612 case PROTECTED : flag = Flags.PROTECTED; break;
3613 case PUBLIC : flag = Flags.PUBLIC; break;
3614 case STATIC : flag = Flags.STATIC; break;
3615 case TRANSIENT : flag = Flags.TRANSIENT; break;
3616 case FINAL : flag = Flags.FINAL; break;
3617 case ABSTRACT : flag = Flags.ABSTRACT; break;
3618 case NATIVE : flag = Flags.NATIVE; break;
3619 case VOLATILE : flag = Flags.VOLATILE; break;
3620 case SYNCHRONIZED: flag = Flags.SYNCHRONIZED; break;
3621 case STRICTFP : flag = Flags.STRICTFP; break;
3622 case MONKEYS_AT : flag = Flags.ANNOTATION; break;
3623 case DEFAULT : flag = Flags.DEFAULT; break;
3624 case ERROR : flag = 0; nextToken(); break;
3625 case IDENTIFIER : {
3626 if (isNonSealedClassStart(false)) {
3627 flag = Flags.NON_SEALED;
3628 nextToken();
3629 nextToken();
3630 break;
3631 }
3632 if (isSealedClassStart(false)) {
3633 checkSourceLevel(Feature.SEALED_CLASSES);
3634 flag = Flags.SEALED;
3635 break;
3636 }
3637 break loop;
3638 }
3639 default: break loop;
3640 }
3641 if ((flags & flag) != 0) log.error(DiagnosticFlag.SYNTAX, token.pos, Errors.RepeatedModifier);
3642 lastPos = token.pos;
3643 nextToken();
3644 if (flag == Flags.ANNOTATION) {
3645 if (token.kind != INTERFACE) {
3646 JCAnnotation ann = annotation(lastPos, Tag.ANNOTATION);
3647 // if first modifier is an annotation, set pos to annotation's.
3648 if (flags == 0 && annotations.isEmpty())
3649 pos = ann.pos;
3650 annotations.append(ann);
3651 flag = 0;
3652 }
3653 }
3654 flags |= flag;
3655 }
3656 switch (token.kind) {
3657 case ENUM: flags |= Flags.ENUM; break;
3658 case INTERFACE: flags |= Flags.INTERFACE; break;
3659 default: break;
3660 }
3661
3662 /* A modifiers tree with no modifier tokens or annotations
3663 * has no text position. */
3664 if ((flags & (Flags.ModifierFlags | Flags.ANNOTATION)) == 0 && annotations.isEmpty())
3665 pos = Position.NOPOS;
3666
3667 JCModifiers mods = F.at(pos).Modifiers(flags, annotations.toList());
3668 if (pos != Position.NOPOS)
3669 storeEnd(mods, S.prevToken().endPos);
3670 return mods;
3671 }
3672
3673 /** Annotation = "@" Qualident [ "(" AnnotationFieldValues ")" ]
3674 *
3675 * @param pos position of "@" token
3676 * @param kind Whether to parse an ANNOTATION or TYPE_ANNOTATION
3677 */
3678 JCAnnotation annotation(int pos, Tag kind) {
3679 // accept(AT); // AT consumed by caller
3680 JCTree ident = qualident(false);
3681 List<JCExpression> fieldValues = annotationFieldValuesOpt();
3682 JCAnnotation ann;
3683 if (kind == Tag.ANNOTATION) {
3684 ann = F.at(pos).Annotation(ident, fieldValues);
3685 } else if (kind == Tag.TYPE_ANNOTATION) {
3686 ann = F.at(pos).TypeAnnotation(ident, fieldValues);
3687 } else {
3688 throw new AssertionError("Unhandled annotation kind: " + kind);
3689 }
3690 return toP(ann);
3691 }
3692
3693 List<JCExpression> annotationFieldValuesOpt() {
3694 return (token.kind == LPAREN) ? annotationFieldValues() : List.nil();
3695 }
3696
3697 /** AnnotationFieldValues = "(" [ AnnotationFieldValue { "," AnnotationFieldValue } ] ")" */
3698 List<JCExpression> annotationFieldValues() {
3699 accept(LPAREN);
3700 ListBuffer<JCExpression> buf = new ListBuffer<>();
3701 if (token.kind != RPAREN) {
3702 buf.append(annotationFieldValue());
3703 while (token.kind == COMMA) {
3704 nextToken();
3705 buf.append(annotationFieldValue());
3706 }
3707 }
3708 accept(RPAREN);
3709 return buf.toList();
3710 }
3711
3712 /** AnnotationFieldValue = AnnotationValue
3713 * | Identifier "=" AnnotationValue
3714 */
3715 JCExpression annotationFieldValue() {
3716 if (LAX_IDENTIFIER.test(token.kind)) {
3717 selectExprMode();
3718 JCExpression t1 = term1();
3719 if (t1.hasTag(IDENT) && token.kind == EQ) {
3720 int pos = token.pos;
3721 accept(EQ);
3722 JCExpression v = annotationValue();
3723 return toP(F.at(pos).Assign(t1, v));
3724 } else {
3725 return t1;
3726 }
3727 }
3728 return annotationValue();
3729 }
3730
3731 /* AnnotationValue = ConditionalExpression
3732 * | Annotation
3733 * | "{" [ AnnotationValue { "," AnnotationValue } ] [","] "}"
3734 */
3735 JCExpression annotationValue() {
3736 int pos;
3737 switch (token.kind) {
3738 case MONKEYS_AT:
3739 pos = token.pos;
3740 nextToken();
3741 return annotation(pos, Tag.ANNOTATION);
3742 case LBRACE:
3743 pos = token.pos;
3744 accept(LBRACE);
3745 ListBuffer<JCExpression> buf = new ListBuffer<>();
3746 if (token.kind == COMMA) {
3747 nextToken();
3748 } else if (token.kind != RBRACE) {
3749 buf.append(annotationValue());
3750 while (token.kind == COMMA) {
3751 nextToken();
3752 if (token.kind == RBRACE) break;
3753 buf.append(annotationValue());
3754 }
3755 }
3756 accept(RBRACE, tk -> Errors.AnnotationMissingElementValue);
3757 return toP(F.at(pos).NewArray(null, List.nil(), buf.toList()));
3758 default:
3759 selectExprMode();
3760 return term1();
3761 }
3762 }
3763
3764 /** VariableDeclarators = VariableDeclarator { "," VariableDeclarator }
3765 */
3766 public <T extends ListBuffer<? super JCVariableDecl>> T variableDeclarators(JCModifiers mods,
3767 JCExpression type,
3768 T vdefs,
3769 boolean localDecl)
3770 {
3771 return variableDeclaratorsRest(token.pos, mods, type, identOrUnderscore(), false, null, vdefs, localDecl);
3772 }
3773
3774 /** VariableDeclaratorsRest = VariableDeclaratorRest { "," VariableDeclarator }
3775 * ConstantDeclaratorsRest = ConstantDeclaratorRest { "," ConstantDeclarator }
3776 *
3777 * @param reqInit Is an initializer always required?
3778 * @param dc The documentation comment for the variable declarations, or null.
3779 */
3780 protected <T extends ListBuffer<? super JCVariableDecl>> T variableDeclaratorsRest(int pos,
3781 JCModifiers mods,
3782 JCExpression type,
3783 Name name,
3784 boolean reqInit,
3785 Comment dc,
3786 T vdefs,
3787 boolean localDecl)
3788 {
3789 JCVariableDecl head = variableDeclaratorRest(pos, mods, type, name, reqInit, dc, localDecl, false);
3790 vdefs.append(head);
3791 while (token.kind == COMMA) {
3792 // All but last of multiple declarators subsume a comma
3793 storeEnd((JCTree)vdefs.last(), token.endPos);
3794 nextToken();
3795 vdefs.append(variableDeclarator(mods, type, reqInit, dc, localDecl));
3796 }
3797 return vdefs;
3798 }
3799
3800 /** VariableDeclarator = Ident VariableDeclaratorRest
3801 * ConstantDeclarator = Ident ConstantDeclaratorRest
3802 */
3803 JCVariableDecl variableDeclarator(JCModifiers mods, JCExpression type, boolean reqInit, Comment dc, boolean localDecl) {
3804 return variableDeclaratorRest(token.pos, mods, type, identOrUnderscore(), reqInit, dc, localDecl, true);
3805 }
3806
3807 /** VariableDeclaratorRest = BracketsOpt ["=" VariableInitializer]
3808 * ConstantDeclaratorRest = BracketsOpt "=" VariableInitializer
3809 *
3810 * @param reqInit Is an initializer always required?
3811 * @param dc The documentation comment for the variable declarations, or null.
3812 */
3813 JCVariableDecl variableDeclaratorRest(int pos, JCModifiers mods, JCExpression type, Name name,
3814 boolean reqInit, Comment dc, boolean localDecl, boolean compound) {
3815 boolean declaredUsingVar = false;
3816 JCExpression init = null;
3817 type = bracketsOpt(type);
3818
3819 if (Feature.UNNAMED_VARIABLES.allowedInSource(source) && name == names.underscore) {
3820 if (!localDecl) {
3821 log.error(DiagnosticFlag.SYNTAX, pos, Errors.UseOfUnderscoreNotAllowed);
3822 }
3823 name = names.empty;
3824 }
3825
3826 saveDanglingDocComments(dc);
3827
3828 if (token.kind == EQ) {
3829 nextToken();
3830 init = variableInitializer();
3831 }
3832 else if (reqInit) syntaxError(token.pos, Errors.Expected(EQ));
3833
3834 if (Feature.UNNAMED_VARIABLES.allowedInSource(source) && name == names.empty
3835 && localDecl
3836 && init == null
3837 && token.kind != COLON) { // if its unnamed local variable, it needs to have an init unless in enhanced-for
3838 syntaxError(token.pos, Errors.Expected(EQ));
3839 }
3840
3841 int varTypePos = Position.NOPOS;
3842 JCTree elemType = TreeInfo.innermostType(type, true);
3843 if (elemType.hasTag(IDENT)) {
3844 Name typeName = ((JCIdent) elemType).name;
3845 if (restrictedTypeNameStartingAtSource(typeName, pos, !compound && localDecl) != null) {
3846 if (typeName != names.var) {
3847 reportSyntaxError(elemType.pos, Errors.RestrictedTypeNotAllowedHere(typeName));
3848 } else if (type.hasTag(TYPEARRAY) && !compound) {
3849 //error - 'var' and arrays
3850 reportSyntaxError(elemType.pos, Errors.RestrictedTypeNotAllowedArray(typeName));
3851 } else {
3852 declaredUsingVar = true;
3853 varTypePos = elemType.pos;
3854 if (compound)
3855 //error - 'var' in compound local var decl
3856 reportSyntaxError(elemType.pos, Errors.RestrictedTypeNotAllowedCompound(typeName));
3857 //implicit type
3858 type = null;
3859 }
3860 }
3861 }
3862 JCVariableDecl result = toP(F.at(pos).VarDef(mods, name, type, init,
3863 declaredUsingVar ? JCVariableDecl.DeclKind.VAR : JCVariableDecl.DeclKind.EXPLICIT, varTypePos));
3864 return attach(result, dc);
3865 }
3866
3867 Name restrictedTypeName(JCExpression e, boolean shouldWarn) {
3868 switch (e.getTag()) {
3869 case IDENT:
3870 return restrictedTypeNameStartingAtSource(((JCIdent)e).name, e.pos, shouldWarn) != null ? ((JCIdent)e).name : null;
3871 case TYPEARRAY:
3872 return restrictedTypeName(((JCArrayTypeTree)e).elemtype, shouldWarn);
3873 default:
3874 return null;
3875 }
3876 }
3877
3878 Source restrictedTypeNameStartingAtSource(Name name, int pos, boolean shouldWarn) {
3879 if (name == names.var) {
3880 if (Feature.LOCAL_VARIABLE_TYPE_INFERENCE.allowedInSource(source)) {
3881 return Source.JDK10;
3882 } else if (shouldWarn) {
3883 log.warning(pos, Warnings.RestrictedTypeNotAllowed(name, Source.JDK10));
3884 }
3885 }
3886 if (name == names.yield) {
3887 if (allowYieldStatement) {
3888 return Source.JDK14;
3889 } else if (shouldWarn) {
3890 log.warning(pos, Warnings.RestrictedTypeNotAllowed(name, Source.JDK14));
3891 }
3892 }
3893 if (name == names.record) {
3894 if (allowRecords) {
3895 return Source.JDK14;
3896 } else if (shouldWarn) {
3897 log.warning(pos, Warnings.RestrictedTypeNotAllowedPreview(name, Source.JDK14));
3898 }
3899 }
3900 if (name == names.sealed) {
3901 if (allowSealedTypes) {
3902 return Source.JDK15;
3903 } else if (shouldWarn) {
3904 log.warning(pos, Warnings.RestrictedTypeNotAllowedPreview(name, Source.JDK15));
3905 }
3906 }
3907 if (name == names.permits) {
3908 if (allowSealedTypes) {
3909 return Source.JDK15;
3910 } else if (shouldWarn) {
3911 log.warning(pos, Warnings.RestrictedTypeNotAllowedPreview(name, Source.JDK15));
3912 }
3913 }
3914 return null;
3915 }
3916
3917 /** VariableDeclaratorId = Ident BracketsOpt
3918 */
3919 JCVariableDecl variableDeclaratorId(JCModifiers mods, JCExpression type, boolean catchParameter, boolean lambdaParameter, boolean recordComponent) {
3920 int pos = token.pos;
3921 Name name;
3922 if (allowThisIdent ||
3923 !lambdaParameter ||
3924 LAX_IDENTIFIER.test(token.kind) ||
3925 mods.flags != Flags.PARAMETER ||
3926 mods.annotations.nonEmpty()) {
3927 JCExpression pn;
3928 if (token.kind == UNDERSCORE && (catchParameter || lambdaParameter)) {
3929 pn = toP(F.at(token.pos).Ident(identOrUnderscore()));
3930 } else {
3931 pn = qualident(false);
3932 }
3933 if (pn.hasTag(Tag.IDENT) && ((JCIdent)pn).name != names._this) {
3934 name = ((JCIdent)pn).name;
3935 } else if (lambdaParameter && type == null) {
3936 // we have a lambda parameter that is not an identifier this is a syntax error
3937 type = pn;
3938 name = names.empty;
3939 reportSyntaxError(pos, Errors.Expected(IDENTIFIER));
3940 } else {
3941 if (allowThisIdent) {
3942 if ((mods.flags & Flags.VARARGS) != 0) {
3943 log.error(token.pos, Errors.VarargsAndReceiver);
3944 }
3945 if (token.kind == LBRACKET) {
3946 log.error(token.pos, Errors.ArrayAndReceiver);
3947 }
3948 if (pn.hasTag(Tag.SELECT) && ((JCFieldAccess)pn).name != names._this) {
3949 log.error(token.pos, Errors.WrongReceiver);
3950 }
3951 }
3952 return toP(F.at(pos).ReceiverVarDef(mods, pn, type));
3953 }
3954 } else {
3955 /** if it is a lambda parameter and the token kind is not an identifier,
3956 * and there are no modifiers or annotations, then this means that the compiler
3957 * supposed the lambda to be explicit but it can contain a mix of implicit,
3958 * var or explicit parameters. So we assign the error name to the parameter name
3959 * instead of issuing an error and analyze the lambda parameters as a whole at
3960 * a higher level.
3961 */
3962 name = names.error;
3963 }
3964 if ((mods.flags & Flags.VARARGS) != 0 &&
3965 token.kind == LBRACKET) {
3966 log.error(token.pos, Errors.VarargsAndOldArraySyntax);
3967 }
3968 if (recordComponent && token.kind == LBRACKET) {
3969 log.error(token.pos, Errors.RecordComponentAndOldArraySyntax);
3970 }
3971 type = bracketsOpt(type);
3972
3973 if (Feature.UNNAMED_VARIABLES.allowedInSource(source) && name == names.underscore) {
3974 name = names.empty;
3975 }
3976
3977 boolean declaredUsingVar = type != null && type.hasTag(IDENT) && ((JCIdent)type).name == names.var;
3978 JCVariableDecl.DeclKind declKind = declaredUsingVar ? JCVariableDecl.DeclKind.VAR :
3979 type != null ? JCVariableDecl.DeclKind.EXPLICIT : JCVariableDecl.DeclKind.IMPLICIT;
3980 int typePos = type != null ? type.pos : pos;
3981 return toP(F.at(pos).VarDef(mods, name, type, null, declKind, typePos));
3982 }
3983
3984 /** Resources = Resource { ";" Resources }
3985 */
3986 List<JCTree> resources() {
3987 ListBuffer<JCTree> defs = new ListBuffer<>();
3988 defs.append(resource());
3989 while (token.kind == SEMI) {
3990 // All but last of multiple declarators must subsume a semicolon
3991 storeEnd(defs.last(), token.endPos);
3992 int semiColonPos = token.pos;
3993 nextToken();
3994 if (token.kind == RPAREN) { // Optional trailing semicolon
3995 // after last resource
3996 break;
3997 }
3998 defs.append(resource());
3999 }
4000 return defs.toList();
4001 }
4002
4003 /** Resource = VariableModifiersOpt Type VariableDeclaratorId "=" Expression
4004 * | Expression
4005 */
4006 protected JCTree resource() {
4007 if (token.kind == FINAL || token.kind == MONKEYS_AT) {
4008 JCModifiers mods = optFinal(0);
4009 JCExpression t = parseType(true);
4010 return variableDeclaratorRest(token.pos, mods, t, identOrUnderscore(), true, null, true, false);
4011 }
4012 JCExpression t = term(EXPR | TYPE);
4013 if (wasTypeMode() && LAX_IDENTIFIER.test(token.kind)) {
4014 JCModifiers mods = F.Modifiers(0);
4015 return variableDeclaratorRest(token.pos, mods, t, identOrUnderscore(), true, null, true, false);
4016 } else {
4017 checkSourceLevel(Feature.EFFECTIVELY_FINAL_VARIABLES_IN_TRY_WITH_RESOURCES);
4018 if (!t.hasTag(IDENT) && !t.hasTag(SELECT)) {
4019 log.error(t.pos(), Errors.TryWithResourcesExprNeedsVar);
4020 }
4021
4022 return t;
4023 }
4024 }
4025
4026 /** CompilationUnit = [ { "@" Annotation } PACKAGE Qualident ";"] {ImportDeclaration} {TypeDeclaration}
4027 */
4028 public JCTree.JCCompilationUnit parseCompilationUnit() {
4029 Token firstToken = token;
4030 JCModifiers mods = null;
4031 boolean consumedToplevelDoc = false;
4032 boolean seenImport = false;
4033 boolean seenPackage = false;
4034 ListBuffer<JCTree> defs = new ListBuffer<>();
4035 if (token.kind == MONKEYS_AT)
4036 mods = modifiersOpt();
4037
4038 if (token.kind == PACKAGE) {
4039 int packagePos = token.pos;
4040 List<JCAnnotation> annotations = List.nil();
4041 seenPackage = true;
4042 if (mods != null) {
4043 checkNoMods(mods.flags & ~Flags.DEPRECATED);
4044 annotations = mods.annotations;
4045 mods = null;
4046 }
4047 nextToken();
4048 JCExpression pid = qualident(false);
4049 accept(SEMI);
4050 JCPackageDecl pd = toP(F.at(packagePos).PackageDecl(annotations, pid));
4051 attach(pd, firstToken.docComment());
4052 consumedToplevelDoc = true;
4053 defs.append(pd);
4054 updateUnexpectedTopLevelDefinitionStartError(true);
4055 }
4056
4057 boolean firstTypeDecl = true; // have we seen a class, enum, or interface declaration yet?
4058 boolean isImplicitClass = false;
4059 OUTER: while (token.kind != EOF) {
4060 if (token.pos <= endPosTable.errorEndPos) {
4061 // error recovery
4062 skip(firstTypeDecl, false, false, false);
4063 if (token.kind == EOF)
4064 break;
4065 }
4066 // JLS 7.3 doesn't allow extra semicolons after package or import declarations,
4067 // but here we try to provide a more helpful error message if we encounter any.
4068 // Do that by slurping in as many semicolons as possible, and then seeing what
4069 // comes after before deciding how best to handle them.
4070 ListBuffer<JCTree> semiList = new ListBuffer<>();
4071 while (firstTypeDecl && mods == null && token.kind == SEMI) {
4072 int pos = token.pos;
4073 nextToken();
4074 semiList.append(toP(F.at(pos).Skip()));
4075 if (token.kind == EOF)
4076 break OUTER;
4077 }
4078 if (firstTypeDecl && mods == null && token.kind == IMPORT) {
4079 if (!semiList.isEmpty()) {
4080 if (source.compareTo(Source.JDK21) >= 0)
4081 reportSyntaxError(semiList.first().pos, Errors.ExtraneousSemicolon);
4082 else
4083 log.warning(semiList.first().pos, Warnings.ExtraneousSemicolon);
4084 }
4085 seenImport = true;
4086 defs.append(importDeclaration());
4087 } else {
4088 Comment docComment = token.docComment();
4089 if (firstTypeDecl && !seenImport && !seenPackage) {
4090 docComment = firstToken.docComment();
4091 consumedToplevelDoc = true;
4092 }
4093 if (mods != null || token.kind != SEMI)
4094 mods = modifiersOpt(mods);
4095 if (firstTypeDecl && token.kind == IDENTIFIER) {
4096 if (!semiList.isEmpty()) {
4097 if (source.compareTo(Source.JDK21) >= 0)
4098 reportSyntaxError(semiList.first().pos, Errors.ExtraneousSemicolon);
4099 else
4100 log.warning(semiList.first().pos, Warnings.ExtraneousSemicolon);
4101 }
4102 ModuleKind kind = ModuleKind.STRONG;
4103 if (token.name() == names.open) {
4104 kind = ModuleKind.OPEN;
4105 nextToken();
4106 }
4107 if (token.kind == IDENTIFIER && token.name() == names.module) {
4108 if (mods != null) {
4109 checkNoMods(mods.flags & ~Flags.DEPRECATED);
4110 }
4111 defs.append(moduleDecl(mods, kind, docComment));
4112 consumedToplevelDoc = true;
4113 break;
4114 } else if (kind != ModuleKind.STRONG) {
4115 reportSyntaxError(token.pos, Errors.ExpectedModule);
4116 }
4117 }
4118
4119 defs.appendList(semiList.toList());
4120 boolean isTopLevelMethodOrField = false;
4121
4122 // Due to a significant number of existing negative tests
4123 // this code speculatively tests to see if a top level method
4124 // or field can parse. If the method or field can parse then
4125 // it is parsed. Otherwise, parsing continues as though
4126 // implicitly declared classes did not exist and error reporting
4127 // is the same as in the past.
4128 if (!isDeclaration(true)) {
4129 final JCModifiers finalMods = mods;
4130 JavacParser speculative = new VirtualParser(this);
4131 List<JCTree> speculativeResult =
4132 speculative.topLevelMethodOrFieldDeclaration(finalMods, null);
4133 if (speculativeResult.head.hasTag(METHODDEF) ||
4134 speculativeResult.head.hasTag(VARDEF)) {
4135 isTopLevelMethodOrField = true;
4136 }
4137 }
4138
4139 if (isTopLevelMethodOrField) {
4140 checkSourceLevel(token.pos, Feature.IMPLICIT_CLASSES);
4141 defs.appendList(topLevelMethodOrFieldDeclaration(mods, docComment));
4142 isImplicitClass = true;
4143 } else if (isDefiniteStatementStartToken()) {
4144 int startPos = token.pos;
4145 List<JCStatement> statements = blockStatement();
4146 defs.append(syntaxError(startPos,
4147 statements,
4148 Errors.StatementNotExpected,
4149 true));
4150 } else {
4151 JCTree def = typeDeclaration(mods, docComment);
4152 if (def instanceof JCExpressionStatement statement)
4153 def = statement.expr;
4154 defs.append(def);
4155 }
4156
4157 mods = null;
4158 firstTypeDecl = false;
4159 }
4160 }
4161 List<JCTree> topLevelDefs = isImplicitClass ? constructImplicitClass(defs.toList(), S.prevToken().endPos) : defs.toList();
4162 JCTree.JCCompilationUnit toplevel = F.at(firstToken.pos).TopLevel(topLevelDefs);
4163 if (!consumedToplevelDoc)
4164 attach(toplevel, firstToken.docComment());
4165 if (defs.isEmpty())
4166 storeEnd(toplevel, S.prevToken().endPos);
4167 if (keepDocComments)
4168 toplevel.docComments = docComments;
4169 if (keepLineMap)
4170 toplevel.lineMap = S.getLineMap();
4171 toplevel.endPositions = this.endPosTable;
4172 return toplevel;
4173 }
4174
4175 // Restructure top level to be an implicitly declared class.
4176 private List<JCTree> constructImplicitClass(List<JCTree> origDefs, int endPos) {
4177 ListBuffer<JCTree> topDefs = new ListBuffer<>();
4178 ListBuffer<JCTree> defs = new ListBuffer<>();
4179
4180 for (JCTree def : origDefs) {
4181 if (def.hasTag(Tag.PACKAGEDEF)) {
4182 log.error(def.pos(), Errors.ImplicitClassShouldNotHavePackageDeclaration);
4183 } else if (def.hasTag(Tag.IMPORT) || def.hasTag(Tag.MODULEIMPORT)) {
4184 topDefs.append(def);
4185 } else if (!def.hasTag(Tag.SKIP)) {
4186 defs.append(def);
4187 }
4188 }
4189
4190 int primaryPos = getStartPos(defs.first());
4191 String simplename = PathFileObject.getSimpleName(log.currentSourceFile());
4192
4193 if (simplename.endsWith(".java")) {
4194 simplename = simplename.substring(0, simplename.length() - ".java".length());
4195 }
4196 if (!SourceVersion.isIdentifier(simplename) || SourceVersion.isKeyword(simplename)) {
4197 log.error(primaryPos, Errors.BadFileName(simplename));
4198 }
4199
4200 Name name = names.fromString(simplename);
4201 JCModifiers implicitMods = F.at(Position.NOPOS)
4202 .Modifiers(Flags.FINAL|Flags.IMPLICIT_CLASS, List.nil());
4203 JCClassDecl implicit = F.at(primaryPos).ClassDef(
4204 implicitMods, name, List.nil(), null, List.nil(), List.nil(),
4205 defs.toList());
4206 storeEnd(implicit, endPos);
4207 topDefs.append(implicit);
4208 return topDefs.toList();
4209 }
4210
4211 JCModuleDecl moduleDecl(JCModifiers mods, ModuleKind kind, Comment dc) {
4212 int pos = token.pos;
4213 checkSourceLevel(Feature.MODULES);
4214
4215 nextToken();
4216 JCExpression name = qualident(false);
4217 List<JCDirective> directives = null;
4218
4219 accept(LBRACE);
4220 directives = moduleDirectiveList();
4221 accept(RBRACE);
4222 int endPos = S.prevToken().endPos;
4223 accept(EOF);
4224
4225 JCModuleDecl result = F.at(pos).ModuleDef(mods, kind, name, directives);
4226 storeEnd(result, endPos);
4227 return attach(result, dc);
4228 }
4229
4230 List<JCDirective> moduleDirectiveList() {
4231 ListBuffer<JCDirective> defs = new ListBuffer<>();
4232 while (token.kind == IDENTIFIER) {
4233 int pos = token.pos;
4234 if (token.name() == names.requires) {
4235 nextToken();
4236 boolean isTransitive = false;
4237 boolean isStaticPhase = false;
4238 loop:
4239 while (true) {
4240 switch (token.kind) {
4241 case IDENTIFIER:
4242 if (token.name() == names.transitive) {
4243 Token t1 = S.token(1);
4244 if (t1.kind == SEMI || t1.kind == DOT) {
4245 break loop;
4246 }
4247 if (isTransitive) {
4248 log.error(DiagnosticFlag.SYNTAX, token.pos, Errors.RepeatedModifier);
4249 }
4250 isTransitive = true;
4251 break;
4252 } else {
4253 break loop;
4254 }
4255 case STATIC:
4256 if (isStaticPhase) {
4257 log.error(DiagnosticFlag.SYNTAX, token.pos, Errors.RepeatedModifier);
4258 }
4259 isStaticPhase = true;
4260 break;
4261 default:
4262 break loop;
4263 }
4264 nextToken();
4265 }
4266 JCExpression moduleName = qualident(false);
4267 accept(SEMI);
4268 defs.append(toP(F.at(pos).Requires(isTransitive, isStaticPhase, moduleName)));
4269 } else if (token.name() == names.exports || token.name() == names.opens) {
4270 boolean exports = token.name() == names.exports;
4271 nextToken();
4272 JCExpression pkgName = qualident(false);
4273 List<JCExpression> moduleNames = null;
4274 if (token.kind == IDENTIFIER && token.name() == names.to) {
4275 nextToken();
4276 moduleNames = qualidentList(false);
4277 }
4278 accept(SEMI);
4279 JCDirective d;
4280 if (exports) {
4281 d = F.at(pos).Exports(pkgName, moduleNames);
4282 } else {
4283 d = F.at(pos).Opens(pkgName, moduleNames);
4284 }
4285 defs.append(toP(d));
4286 } else if (token.name() == names.provides) {
4287 nextToken();
4288 JCExpression serviceName = qualident(false);
4289 List<JCExpression> implNames;
4290 if (token.kind == IDENTIFIER && token.name() == names.with) {
4291 nextToken();
4292 implNames = qualidentList(false);
4293 } else {
4294 log.error(DiagnosticFlag.SYNTAX, token.pos, Errors.ExpectedStr("'" + names.with + "'"));
4295 implNames = List.nil();
4296 }
4297 accept(SEMI);
4298 defs.append(toP(F.at(pos).Provides(serviceName, implNames)));
4299 } else if (token.name() == names.uses) {
4300 nextToken();
4301 JCExpression service = qualident(false);
4302 accept(SEMI);
4303 defs.append(toP(F.at(pos).Uses(service)));
4304 } else {
4305 setErrorEndPos(pos);
4306 reportSyntaxError(pos, Errors.InvalidModuleDirective);
4307 break;
4308 }
4309 }
4310 return defs.toList();
4311 }
4312
4313 /** ImportDeclaration = IMPORT [ STATIC ] Ident { "." Ident } [ "." "*" ] ";"
4314 */
4315 protected JCTree importDeclaration() {
4316 int pos = token.pos;
4317 nextToken();
4318 boolean importStatic = false;
4319 if (token.kind == STATIC) {
4320 importStatic = true;
4321 nextToken();
4322 } else if (token.kind == IDENTIFIER && token.name() == names.module &&
4323 peekToken(TokenKind.IDENTIFIER)) {
4324 checkSourceLevel(Feature.MODULE_IMPORTS);
4325 nextToken();
4326 JCExpression moduleName = qualident(false);
4327 accept(SEMI);
4328 return toP(F.at(pos).ModuleImport(moduleName));
4329 }
4330 JCExpression pid = toP(F.at(token.pos).Ident(ident()));
4331 do {
4332 int pos1 = token.pos;
4333 accept(DOT);
4334 if (token.kind == STAR) {
4335 pid = to(F.at(pos1).Select(pid, names.asterisk));
4336 nextToken();
4337 break;
4338 } else {
4339 pid = toP(F.at(pos1).Select(pid, ident()));
4340 }
4341 } while (token.kind == DOT);
4342 accept(SEMI);
4343 return toP(F.at(pos).Import((JCFieldAccess)pid, importStatic));
4344 }
4345
4346 /** TypeDeclaration = ClassOrInterfaceOrEnumDeclaration
4347 * | ";"
4348 */
4349 JCTree typeDeclaration(JCModifiers mods, Comment docComment) {
4350 int pos = token.pos;
4351 if (mods == null && token.kind == SEMI) {
4352 nextToken();
4353 return toP(F.at(pos).Skip());
4354 } else {
4355 return classOrRecordOrInterfaceOrEnumDeclaration(modifiersOpt(mods), docComment);
4356 }
4357 }
4358
4359 /** ClassOrInterfaceOrEnumDeclaration = ModifiersOpt
4360 * (ClassDeclaration | InterfaceDeclaration | EnumDeclaration)
4361 * @param mods Any modifiers starting the class or interface declaration
4362 * @param dc The documentation comment for the class, or null.
4363 */
4364 protected JCStatement classOrRecordOrInterfaceOrEnumDeclaration(JCModifiers mods, Comment dc) {
4365 if (token.kind == CLASS) {
4366 return classDeclaration(mods, dc);
4367 } if (isRecordStart()) {
4368 return recordDeclaration(mods, dc);
4369 } else if (token.kind == INTERFACE) {
4370 return interfaceDeclaration(mods, dc);
4371 } else if (token.kind == ENUM) {
4372 return enumDeclaration(mods, dc);
4373 } else {
4374 int pos = token.pos;
4375 List<JCTree> errs;
4376 if (LAX_IDENTIFIER.test(token.kind)) {
4377 errs = List.of(mods, toP(F.at(pos).Ident(ident())));
4378 setErrorEndPos(token.pos);
4379 } else {
4380 errs = List.of(mods);
4381 }
4382
4383 return toP(F.Exec(syntaxError(pos, errs, unexpectedTopLevelDefinitionStartError)));
4384
4385 }
4386 }
4387
4388 /** ClassDeclaration = CLASS Ident TypeParametersOpt [EXTENDS Type]
4389 * [IMPLEMENTS TypeList] ClassBody
4390 * @param mods The modifiers starting the class declaration
4391 * @param dc The documentation comment for the class, or null.
4392 */
4393 protected JCClassDecl classDeclaration(JCModifiers mods, Comment dc) {
4394 int pos = token.pos;
4395 accept(CLASS);
4396 Name name = typeName();
4397
4398 List<JCTypeParameter> typarams = typeParametersOpt();
4399
4400 JCExpression extending = null;
4401 if (token.kind == EXTENDS) {
4402 nextToken();
4403 extending = parseType();
4404 }
4405 List<JCExpression> implementing = List.nil();
4406 if (token.kind == IMPLEMENTS) {
4407 nextToken();
4408 implementing = typeList();
4409 }
4410 List<JCExpression> permitting = permitsClause(mods, "class");
4411
4412 saveDanglingDocComments(dc);
4413
4414 List<JCTree> defs = classInterfaceOrRecordBody(name, false, false);
4415 JCClassDecl result = toP(F.at(pos).ClassDef(
4416 mods, name, typarams, extending, implementing, permitting, defs));
4417 return attach(result, dc);
4418 }
4419
4420 protected JCClassDecl recordDeclaration(JCModifiers mods, Comment dc) {
4421 int pos = token.pos;
4422 nextToken();
4423 mods.flags |= Flags.RECORD;
4424 Name name = typeName();
4425
4426 List<JCTypeParameter> typarams = typeParametersOpt();
4427
4428 List<JCVariableDecl> headerFields = formalParameters(false, true);
4429
4430 List<JCExpression> implementing = List.nil();
4431 if (token.kind == IMPLEMENTS) {
4432 nextToken();
4433 implementing = typeList();
4434 }
4435
4436 saveDanglingDocComments(dc);
4437
4438 List<JCTree> defs = classInterfaceOrRecordBody(name, false, true);
4439 java.util.List<JCVariableDecl> fields = new ArrayList<>();
4440 for (JCVariableDecl field : headerFields) {
4441 fields.add(field);
4442 }
4443 for (JCTree def : defs) {
4444 if (def.hasTag(METHODDEF)) {
4445 JCMethodDecl methDef = (JCMethodDecl) def;
4446 if (methDef.name == names.init && methDef.params.isEmpty() && (methDef.mods.flags & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0) {
4447 ListBuffer<JCVariableDecl> tmpParams = new ListBuffer<>();
4448 for (JCVariableDecl param : headerFields) {
4449 tmpParams.add(F.at(param)
4450 // we will get flags plus annotations from the record component
4451 .VarDef(F.Modifiers(Flags.PARAMETER | Flags.GENERATED_MEMBER | Flags.MANDATED | param.mods.flags & Flags.VARARGS,
4452 param.mods.annotations),
4453 param.name, param.vartype, null));
4454 }
4455 methDef.params = tmpParams.toList();
4456 }
4457 }
4458 }
4459 for (int i = fields.size() - 1; i >= 0; i--) {
4460 JCVariableDecl field = fields.get(i);
4461 defs = defs.prepend(field);
4462 }
4463 JCClassDecl result = toP(F.at(pos).ClassDef(mods, name, typarams, null, implementing, defs));
4464 return attach(result, dc);
4465 }
4466
4467 Name typeName() {
4468 int pos = token.pos;
4469 Name name = ident();
4470 Source source = restrictedTypeNameStartingAtSource(name, pos, true);
4471 if (source != null) {
4472 reportSyntaxError(pos, Errors.RestrictedTypeNotAllowed(name, source));
4473 }
4474 return name;
4475 }
4476
4477 /** InterfaceDeclaration = INTERFACE Ident TypeParametersOpt
4478 * [EXTENDS TypeList] InterfaceBody
4479 * @param mods The modifiers starting the interface declaration
4480 * @param dc The documentation comment for the interface, or null.
4481 */
4482 protected JCClassDecl interfaceDeclaration(JCModifiers mods, Comment dc) {
4483 int pos = token.pos;
4484 accept(INTERFACE);
4485
4486 Name name = typeName();
4487
4488 List<JCTypeParameter> typarams = typeParametersOpt();
4489
4490 List<JCExpression> extending = List.nil();
4491 if (token.kind == EXTENDS) {
4492 nextToken();
4493 extending = typeList();
4494 }
4495 List<JCExpression> permitting = permitsClause(mods, "interface");
4496
4497 saveDanglingDocComments(dc);
4498
4499 List<JCTree> defs;
4500 defs = classInterfaceOrRecordBody(name, true, false);
4501 JCClassDecl result = toP(F.at(pos).ClassDef(
4502 mods, name, typarams, null, extending, permitting, defs));
4503 return attach(result, dc);
4504 }
4505
4506 List<JCExpression> permitsClause(JCModifiers mods, String classOrInterface) {
4507 if (allowSealedTypes && token.kind == IDENTIFIER && token.name() == names.permits) {
4508 checkSourceLevel(Feature.SEALED_CLASSES);
4509 if ((mods.flags & Flags.SEALED) == 0) {
4510 log.error(token.pos, Errors.InvalidPermitsClause(Fragments.ClassIsNotSealed(classOrInterface)));
4511 }
4512 nextToken();
4513 return qualidentList(false);
4514 }
4515 return List.nil();
4516 }
4517
4518 /** EnumDeclaration = ENUM Ident [IMPLEMENTS TypeList] EnumBody
4519 * @param mods The modifiers starting the enum declaration
4520 * @param dc The documentation comment for the enum, or null.
4521 */
4522 protected JCClassDecl enumDeclaration(JCModifiers mods, Comment dc) {
4523 int pos = token.pos;
4524 accept(ENUM);
4525
4526 Name name = typeName();
4527
4528 int typeNamePos = token.pos;
4529 List<JCTypeParameter> typarams = typeParametersOpt(true);
4530 if (typarams == null || !typarams.isEmpty()) {
4531 int errorPosition = typarams == null
4532 ? typeNamePos
4533 : typarams.head.pos;
4534 log.error(DiagnosticFlag.SYNTAX, errorPosition, Errors.EnumCantBeGeneric);
4535 }
4536
4537 List<JCExpression> implementing = List.nil();
4538 if (token.kind == IMPLEMENTS) {
4539 nextToken();
4540 implementing = typeList();
4541 }
4542
4543 saveDanglingDocComments(dc);
4544
4545 List<JCTree> defs = enumBody(name);
4546 mods.flags |= Flags.ENUM;
4547 JCClassDecl result = toP(F.at(pos).
4548 ClassDef(mods, name, List.nil(),
4549 null, implementing, defs));
4550 return attach(result, dc);
4551 }
4552
4553 /** EnumBody = "{" { EnumeratorDeclarationList } [","]
4554 * [ ";" {ClassBodyDeclaration} ] "}"
4555 */
4556 List<JCTree> enumBody(Name enumName) {
4557 accept(LBRACE);
4558 ListBuffer<JCTree> defs = new ListBuffer<>();
4559 boolean wasSemi = false;
4560 boolean hasStructuralErrors = false;
4561 boolean wasError = false;
4562 if (token.kind == COMMA) {
4563 nextToken();
4564 if (token.kind == SEMI) {
4565 wasSemi = true;
4566 nextToken();
4567 } else if (token.kind != RBRACE) {
4568 reportSyntaxError(S.prevToken().endPos,
4569 Errors.Expected2(RBRACE, SEMI));
4570 wasError = true;
4571 }
4572 }
4573 while (token.kind != RBRACE && token.kind != EOF) {
4574 if (token.kind == SEMI) {
4575 accept(SEMI);
4576 wasSemi = true;
4577 if (token.kind == RBRACE || token.kind == EOF) break;
4578 }
4579 EnumeratorEstimate memberType = estimateEnumeratorOrMember(enumName);
4580 if (memberType == EnumeratorEstimate.UNKNOWN) {
4581 memberType = wasSemi ? EnumeratorEstimate.MEMBER
4582 : EnumeratorEstimate.ENUMERATOR;
4583 }
4584 if (memberType == EnumeratorEstimate.ENUMERATOR) {
4585 wasError = false;
4586 if (wasSemi && !hasStructuralErrors) {
4587 reportSyntaxError(token.pos, Errors.EnumConstantNotExpected);
4588 hasStructuralErrors = true;
4589 }
4590 defs.append(enumeratorDeclaration(enumName));
4591 if (token.pos <= endPosTable.errorEndPos) {
4592 // error recovery
4593 skip(false, true, true, false);
4594 } else {
4595 if (token.kind != RBRACE && token.kind != SEMI && token.kind != EOF) {
4596 if (token.kind == COMMA) {
4597 nextToken();
4598 } else {
4599 setErrorEndPos(token.pos);
4600 reportSyntaxError(S.prevToken().endPos,
4601 Errors.Expected3(COMMA, RBRACE, SEMI));
4602 wasError = true;
4603 }
4604 }
4605 }
4606 } else {
4607 if (!wasSemi && !hasStructuralErrors && !wasError) {
4608 reportSyntaxError(token.pos, Errors.EnumConstantExpected);
4609 hasStructuralErrors = true;
4610 }
4611 wasError = false;
4612 defs.appendList(classOrInterfaceOrRecordBodyDeclaration(null, enumName,
4613 false, false));
4614 if (token.pos <= endPosTable.errorEndPos) {
4615 // error recovery
4616 skip(false, true, true, false);
4617 }
4618 }
4619 }
4620 accept(RBRACE);
4621 return defs.toList();
4622 }
4623
4624 @SuppressWarnings("fallthrough")
4625 private EnumeratorEstimate estimateEnumeratorOrMember(Name enumName) {
4626 // if we are seeing a record declaration inside of an enum we want the same error message as expected for a
4627 // let's say an interface declaration inside an enum
4628 boolean ident = token.kind == TokenKind.IDENTIFIER ||
4629 token.kind == TokenKind.UNDERSCORE;
4630 if (ident && token.name() != enumName &&
4631 (!allowRecords || !isRecordStart())) {
4632 Token next = S.token(1);
4633 switch (next.kind) {
4634 case LPAREN: case LBRACE: case COMMA: case SEMI:
4635 return EnumeratorEstimate.ENUMERATOR;
4636 }
4637 }
4638 switch (token.kind) {
4639 case IDENTIFIER:
4640 if (allowRecords && isRecordStart()) {
4641 return EnumeratorEstimate.MEMBER;
4642 }
4643 case MONKEYS_AT: case LT: case UNDERSCORE:
4644 return EnumeratorEstimate.UNKNOWN;
4645 default:
4646 return EnumeratorEstimate.MEMBER;
4647 }
4648 }
4649
4650 private enum EnumeratorEstimate {
4651 ENUMERATOR,
4652 MEMBER,
4653 UNKNOWN;
4654 }
4655
4656 /** EnumeratorDeclaration = AnnotationsOpt [TypeArguments] IDENTIFIER [ Arguments ] [ "{" ClassBody "}" ]
4657 */
4658 JCTree enumeratorDeclaration(Name enumName) {
4659 Comment dc = token.docComment();
4660 int flags = Flags.PUBLIC|Flags.STATIC|Flags.FINAL|Flags.ENUM;
4661 if (token.deprecatedFlag()) {
4662 flags |= Flags.DEPRECATED;
4663 }
4664 int pos = token.pos;
4665 List<JCAnnotation> annotations = annotationsOpt(Tag.ANNOTATION);
4666 JCModifiers mods = F.at(annotations.isEmpty() ? Position.NOPOS : pos).Modifiers(flags, annotations);
4667 List<JCExpression> typeArgs = typeArgumentsOpt();
4668 int identPos = token.pos;
4669 Name name = ident();
4670 int createPos = token.pos;
4671
4672 saveDanglingDocComments(dc);
4673
4674 List<JCExpression> args = (token.kind == LPAREN)
4675 ? arguments() : List.nil();
4676
4677 JCClassDecl body = null;
4678 if (token.kind == LBRACE) {
4679 JCModifiers mods1 = F.at(Position.NOPOS).Modifiers(Flags.ENUM);
4680 List<JCTree> defs = classInterfaceOrRecordBody(names.empty, false, false);
4681 body = toP(F.at(identPos).AnonymousClassDef(mods1, defs));
4682 }
4683 if (args.isEmpty() && body == null)
4684 createPos = identPos;
4685 JCIdent ident = F.at(identPos).Ident(enumName);
4686 JCNewClass create = F.at(createPos).NewClass(null, typeArgs, ident, args, body);
4687 if (createPos != identPos)
4688 storeEnd(create, S.prevToken().endPos);
4689 ident = F.at(identPos).Ident(enumName);
4690 JCTree result = toP(F.at(pos).VarDef(mods, name, ident, create));
4691 return attach(result, dc);
4692 }
4693
4694 /** TypeList = Type {"," Type}
4695 */
4696 List<JCExpression> typeList() {
4697 ListBuffer<JCExpression> ts = new ListBuffer<>();
4698 ts.append(parseType());
4699 while (token.kind == COMMA) {
4700 nextToken();
4701 ts.append(parseType());
4702 }
4703 return ts.toList();
4704 }
4705
4706 /** ClassBody = "{" {ClassBodyDeclaration} "}"
4707 * InterfaceBody = "{" {InterfaceBodyDeclaration} "}"
4708 */
4709 List<JCTree> classInterfaceOrRecordBody(Name className, boolean isInterface, boolean isRecord) {
4710 accept(LBRACE);
4711 if (token.pos <= endPosTable.errorEndPos) {
4712 // error recovery
4713 skip(false, true, false, false);
4714 if (token.kind == LBRACE)
4715 nextToken();
4716 else
4717 return List.nil();
4718 }
4719 ListBuffer<JCTree> defs = new ListBuffer<>();
4720 while (token.kind != RBRACE && token.kind != EOF) {
4721 defs.appendList(classOrInterfaceOrRecordBodyDeclaration(null, className, isInterface, isRecord));
4722 if (token.pos <= endPosTable.errorEndPos) {
4723 // error recovery
4724 skip(false, true, true, false);
4725 }
4726 }
4727 accept(RBRACE);
4728 return defs.toList();
4729 }
4730
4731 /** ClassBodyDeclaration =
4732 * ";"
4733 * | [STATIC] Block
4734 * | ModifiersOpt
4735 * ( Type Ident
4736 * ( VariableDeclaratorsRest ";" | MethodDeclaratorRest )
4737 * | VOID Ident VoidMethodDeclaratorRest
4738 * | TypeParameters [Annotations]
4739 * ( Type Ident MethodDeclaratorRest
4740 * | VOID Ident VoidMethodDeclaratorRest
4741 * )
4742 * | Ident ConstructorDeclaratorRest
4743 * | TypeParameters Ident ConstructorDeclaratorRest
4744 * | ClassOrInterfaceOrEnumDeclaration
4745 * )
4746 * InterfaceBodyDeclaration =
4747 * ";"
4748 * | ModifiersOpt
4749 * ( Type Ident
4750 * ( ConstantDeclaratorsRest ";" | MethodDeclaratorRest )
4751 * | VOID Ident MethodDeclaratorRest
4752 * | TypeParameters [Annotations]
4753 * ( Type Ident MethodDeclaratorRest
4754 * | VOID Ident VoidMethodDeclaratorRest
4755 * )
4756 * | ClassOrInterfaceOrEnumDeclaration
4757 * )
4758 *
4759 */
4760 protected List<JCTree> classOrInterfaceOrRecordBodyDeclaration(JCModifiers mods, Name className,
4761 boolean isInterface,
4762 boolean isRecord) {
4763 if (token.kind == SEMI) {
4764 nextToken();
4765 return List.nil();
4766 } else {
4767 Comment dc = token.docComment();
4768 int pos = token.pos;
4769 mods = modifiersOpt(mods);
4770 if (isDeclaration()) {
4771 return List.of(classOrRecordOrInterfaceOrEnumDeclaration(mods, dc));
4772 } else if (token.kind == LBRACE &&
4773 (mods.flags & Flags.StandardFlags & ~Flags.STATIC) == 0 &&
4774 mods.annotations.isEmpty()) {
4775 if (isInterface) {
4776 log.error(DiagnosticFlag.SYNTAX, token.pos, Errors.InitializerNotAllowed);
4777 } else if (isRecord && (mods.flags & Flags.STATIC) == 0) {
4778 log.error(DiagnosticFlag.SYNTAX, token.pos, Errors.InstanceInitializerNotAllowedInRecords);
4779 }
4780 ignoreDanglingComments(); // no declaration with which dangling comments can be associated
4781 return List.of(block(pos, mods.flags));
4782 } else if (isDefiniteStatementStartToken()) {
4783 int startPos = token.pos;
4784 List<JCStatement> statements = blockStatement();
4785 return List.of(syntaxError(startPos,
4786 statements,
4787 Errors.StatementNotExpected));
4788 } else {
4789 return constructorOrMethodOrFieldDeclaration(mods, className, isInterface, isRecord, dc);
4790 }
4791 }
4792 }
4793
4794 private List<JCTree> constructorOrMethodOrFieldDeclaration(JCModifiers mods, Name className,
4795 boolean isInterface,
4796 boolean isRecord, Comment dc) {
4797 int pos;
4798 pos = token.pos;
4799 List<JCTypeParameter> typarams = typeParametersOpt();
4800 // if there are type parameters but no modifiers, save the start
4801 // position of the method in the modifiers.
4802 if (typarams.nonEmpty() && mods.pos == Position.NOPOS) {
4803 mods.pos = pos;
4804 storeEnd(mods, pos);
4805 }
4806 List<JCAnnotation> annosAfterParams = annotationsOpt(Tag.ANNOTATION);
4807
4808 if (annosAfterParams.nonEmpty()) {
4809 mods.annotations = mods.annotations.appendList(annosAfterParams);
4810 if (mods.pos == Position.NOPOS)
4811 mods.pos = mods.annotations.head.pos;
4812 }
4813
4814 Token tk = token;
4815 pos = token.pos;
4816 JCExpression type;
4817 boolean isVoid = token.kind == VOID;
4818
4819 if (isVoid) {
4820 type = to(F.at(pos).TypeIdent(TypeTag.VOID));
4821 nextToken();
4822 } else {
4823 // method returns types are un-annotated types
4824 type = unannotatedType(false);
4825 }
4826
4827 // Constructor
4828 if ((token.kind == LPAREN && !isInterface ||
4829 isRecord && token.kind == LBRACE) && type.hasTag(IDENT)) {
4830 if (isInterface || tk.name() != className) {
4831 log.error(DiagnosticFlag.SYNTAX, pos, Errors.InvalidMethDeclRetTypeReq);
4832 } else if (annosAfterParams.nonEmpty()) {
4833 illegal(annosAfterParams.head.pos);
4834 }
4835
4836 if (isRecord && token.kind == LBRACE) {
4837 mods.flags |= Flags.COMPACT_RECORD_CONSTRUCTOR;
4838 }
4839
4840 return List.of(methodDeclaratorRest(
4841 pos, mods, null, names.init, typarams,
4842 isInterface, true, isRecord, dc));
4843 }
4844
4845 // Record constructor
4846 if (isRecord && type.hasTag(IDENT) && token.kind == THROWS) {
4847 // trying to define a compact constructor with a throws clause
4848 log.error(DiagnosticFlag.SYNTAX, token.pos,
4849 Errors.InvalidCanonicalConstructorInRecord(
4850 Fragments.Compact,
4851 className,
4852 Fragments.ThrowsClauseNotAllowedForCanonicalConstructor(Fragments.Compact)));
4853 skip(false, true, false, false);
4854 return List.of(methodDeclaratorRest(
4855 pos, mods, null, names.init, typarams,
4856 isInterface, true, isRecord, dc));
4857 }
4858
4859 pos = token.pos;
4860 Name name = ident();
4861
4862 // Method
4863 if (token.kind == LPAREN) {
4864 return List.of(methodDeclaratorRest(
4865 pos, mods, type, name, typarams,
4866 isInterface, isVoid, false, dc));
4867 }
4868
4869 // Field
4870 if (!isVoid && typarams.isEmpty()) {
4871 if (!isRecord || (isRecord && (mods.flags & Flags.STATIC) != 0)) {
4872 List<JCTree> defs =
4873 variableDeclaratorsRest(pos, mods, type, name, isInterface, dc,
4874 new ListBuffer<JCTree>(), false).toList();
4875 accept(SEMI);
4876 storeEnd(defs.last(), S.prevToken().endPos);
4877 return defs;
4878 }
4879
4880 int errPos = pos;
4881 variableDeclaratorsRest(pos, mods, type, name, isInterface, dc,
4882 new ListBuffer<JCTree>(), false).toList();
4883 accept(SEMI);
4884 return List.of(syntaxError(errPos, null, Errors.RecordCannotDeclareInstanceFields));
4885 }
4886
4887 pos = token.pos;
4888 List<JCTree> err;
4889
4890 // Error recovery
4891 if (isVoid || typarams.nonEmpty()) {
4892 JCMethodDecl m =
4893 toP(F.at(pos).MethodDef(mods, name, type, typarams,
4894 List.nil(), List.nil(), null, null));
4895 attach(m, dc);
4896 err = List.of(m);
4897 } else {
4898 err = List.nil();
4899 }
4900
4901 return List.of(syntaxError(token.pos, err, Errors.Expected(LPAREN)));
4902 }
4903
4904 private List<JCTree> topLevelMethodOrFieldDeclaration(JCModifiers mods, Comment dc) throws AssertionError {
4905 int pos = token.pos;
4906 dc = dc == null ? token.docComment() : dc;
4907 List<JCTypeParameter> typarams = typeParametersOpt();
4908
4909 // if there are type parameters but no modifiers, save the start
4910 // position of the method in the modifiers.
4911 if (typarams.nonEmpty() && mods.pos == Position.NOPOS) {
4912 mods.pos = pos;
4913 storeEnd(mods, pos);
4914 }
4915
4916 List<JCAnnotation> annosAfterParams = annotationsOpt(Tag.ANNOTATION);
4917
4918 if (annosAfterParams.nonEmpty()) {
4919 mods.annotations = mods.annotations.appendList(annosAfterParams);
4920 if (mods.pos == Position.NOPOS)
4921 mods.pos = mods.annotations.head.pos;
4922 }
4923
4924 pos = token.pos;
4925 JCExpression type;
4926 boolean isVoid = token.kind == VOID;
4927
4928 if (isVoid) {
4929 type = to(F.at(pos).TypeIdent(TypeTag.VOID));
4930 nextToken();
4931 } else {
4932 type = unannotatedType(false);
4933 }
4934
4935 if (token.kind == IDENTIFIER) {
4936 pos = token.pos;
4937 Name name = ident();
4938
4939 // Method
4940 if (token.kind == LPAREN) {
4941 return List.of(methodDeclaratorRest(pos, mods, type, name, typarams,
4942 false, isVoid, false, dc));
4943 }
4944
4945 // Field
4946 if (!isVoid && typarams.isEmpty() &&
4947 (token.kind == EQ || token.kind == SEMI || token.kind == COMMA)) {
4948 List<JCTree> defs =
4949 variableDeclaratorsRest(pos, mods, type, name, false, dc,
4950 new ListBuffer<JCTree>(), false).toList();
4951 accept(SEMI);
4952 storeEnd(defs.last(), S.prevToken().endPos);
4953
4954 return defs;
4955 }
4956 } else if (token.kind == LPAREN && type.hasTag(IDENT)) {
4957 log.error(DiagnosticFlag.SYNTAX, pos, Errors.InvalidMethDeclRetTypeReq);
4958
4959 return List.of(methodDeclaratorRest(
4960 pos, mods, null, names.init, typarams,
4961 false, true, false, dc));
4962 }
4963
4964 return List.of(F.Erroneous());
4965 }
4966
4967 protected boolean isDeclaration() {
4968 return isDeclaration(allowRecords);
4969 }
4970
4971 private boolean isDeclaration(boolean allowRecords) {
4972 return token.kind == CLASS ||
4973 token.kind == INTERFACE ||
4974 token.kind == ENUM ||
4975 isRecordStart() && allowRecords;
4976 }
4977
4978 /**
4979 * {@return true if and only if the current token is definitelly a token that
4980 * starts a statement.}
4981 */
4982 private boolean isDefiniteStatementStartToken() {
4983 return switch (token.kind) {
4984 case IF, WHILE, DO, SWITCH, RETURN, TRY, FOR, ASSERT, BREAK,
4985 CONTINUE, THROW -> true;
4986 default -> false;
4987 };
4988 }
4989
4990 protected boolean isRecordStart() {
4991 if (token.kind == IDENTIFIER && token.name() == names.record && peekToken(TokenKind.IDENTIFIER)) {
4992 checkSourceLevel(Feature.RECORDS);
4993 return true;
4994 } else {
4995 return false;
4996 }
4997 }
4998
4999 protected boolean isNonSealedClassStart(boolean local) {
5000 if (isNonSealedIdentifier(token, 0)) {
5001 Token next = S.token(3);
5002 return allowedAfterSealedOrNonSealed(next, local, true);
5003 }
5004 return false;
5005 }
5006
5007 protected boolean isNonSealedIdentifier(Token someToken, int lookAheadOffset) {
5008 if (someToken.name() == names.non && peekToken(lookAheadOffset, TokenKind.SUB, TokenKind.IDENTIFIER)) {
5009 Token tokenSub = S.token(lookAheadOffset + 1);
5010 Token tokenSealed = S.token(lookAheadOffset + 2);
5011 if (someToken.endPos == tokenSub.pos &&
5012 tokenSub.endPos == tokenSealed.pos &&
5013 tokenSealed.name() == names.sealed) {
5014 checkSourceLevel(Feature.SEALED_CLASSES);
5015 return true;
5016 }
5017 }
5018 return false;
5019 }
5020
5021 protected boolean isSealedClassStart(boolean local) {
5022 if (token.name() == names.sealed) {
5023 Token next = S.token(1);
5024 if (allowedAfterSealedOrNonSealed(next, local, false)) {
5025 checkSourceLevel(Feature.SEALED_CLASSES);
5026 return true;
5027 }
5028 }
5029 return false;
5030 }
5031
5032 private boolean allowedAfterSealedOrNonSealed(Token next, boolean local, boolean currentIsNonSealed) {
5033 return local ?
5034 switch (next.kind) {
5035 case MONKEYS_AT -> {
5036 Token afterNext = S.token(2);
5037 yield afterNext.kind != INTERFACE || currentIsNonSealed;
5038 }
5039 case ABSTRACT, FINAL, STRICTFP, CLASS, INTERFACE, ENUM -> true;
5040 default -> false;
5041 } :
5042 switch (next.kind) {
5043 case MONKEYS_AT -> {
5044 Token afterNext = S.token(2);
5045 yield afterNext.kind != INTERFACE || currentIsNonSealed;
5046 }
5047 case PUBLIC, PROTECTED, PRIVATE, ABSTRACT, STATIC, FINAL, STRICTFP, CLASS, INTERFACE, ENUM -> true;
5048 case IDENTIFIER -> isNonSealedIdentifier(next, currentIsNonSealed ? 3 : 1) || next.name() == names.sealed;
5049 default -> false;
5050 };
5051 }
5052
5053 /** MethodDeclaratorRest =
5054 * FormalParameters BracketsOpt [THROWS TypeList] ( MethodBody | [DEFAULT AnnotationValue] ";")
5055 * VoidMethodDeclaratorRest =
5056 * FormalParameters [THROWS TypeList] ( MethodBody | ";")
5057 * ConstructorDeclaratorRest =
5058 * "(" FormalParameterListOpt ")" [THROWS TypeList] MethodBody
5059 */
5060 protected JCTree methodDeclaratorRest(int pos,
5061 JCModifiers mods,
5062 JCExpression type,
5063 Name name,
5064 List<JCTypeParameter> typarams,
5065 boolean isInterface, boolean isVoid,
5066 boolean isRecord,
5067 Comment dc) {
5068 if (isInterface) {
5069 if ((mods.flags & Flags.PRIVATE) != 0) {
5070 checkSourceLevel(Feature.PRIVATE_INTERFACE_METHODS);
5071 }
5072 }
5073 JCVariableDecl prevReceiverParam = this.receiverParam;
5074 try {
5075 this.receiverParam = null;
5076 // Parsing formalParameters sets the receiverParam, if present
5077 List<JCVariableDecl> params = List.nil();
5078 List<JCExpression> thrown = List.nil();
5079 boolean unclosedParameterList;
5080 if (!isRecord || name != names.init || token.kind == LPAREN) {
5081 params = formalParameters();
5082 unclosedParameterList = token.pos == endPosTable.errorEndPos;
5083 if (!isVoid) type = bracketsOpt(type);
5084 if (token.kind == THROWS) {
5085 nextToken();
5086 thrown = qualidentList(true);
5087 }
5088 } else {
5089 unclosedParameterList = false;
5090 }
5091
5092 saveDanglingDocComments(dc);
5093
5094 JCBlock body = null;
5095 JCExpression defaultValue;
5096 if (token.kind == LBRACE) {
5097 body = block();
5098 defaultValue = null;
5099 } else {
5100 if (token.kind == DEFAULT) {
5101 accept(DEFAULT);
5102 defaultValue = annotationValue();
5103 accept(SEMI);
5104 } else {
5105 defaultValue = null;
5106 accept(SEMI, tk -> Errors.Expected2(LBRACE, SEMI));
5107 }
5108 if (token.pos <= endPosTable.errorEndPos) {
5109 // error recovery
5110 // look if there is a probable missing opening brace,
5111 // and if yes, parse as a block
5112 boolean parseAsBlock = openingBraceMissing(unclosedParameterList);
5113
5114 if (parseAsBlock) {
5115 body = block();
5116 }
5117 }
5118 }
5119
5120 JCMethodDecl result =
5121 toP(F.at(pos).MethodDef(mods, name, type, typarams,
5122 receiverParam, params, thrown,
5123 body, defaultValue));
5124 return attach(result, dc);
5125 } finally {
5126 this.receiverParam = prevReceiverParam;
5127 }
5128 }
5129
5130 /**
5131 * After seeing a method header, and not seeing an opening left brace,
5132 * attempt to estimate if acting as if the left brace was present and
5133 * parsing the upcoming code will get better results than not parsing
5134 * the code as a block.
5135 *
5136 * The estimate is as follows:
5137 * - tokens are skipped until member, statement or identifier is found,
5138 * - then, if there is a left brace, parse as a block,
5139 * - otherwise, if the head was broken, do not parse as a block,
5140 * - otherwise, look at the next token and:
5141 * - if it definitelly starts a statement, parse as a block,
5142 * - otherwise, if it is a closing/right brace, count opening and closing
5143 * braces in the rest of the file, to see if imaginarily "adding" an opening
5144 * brace would lead to a balanced count - if yes, parse as a block,
5145 * - otherwise, speculatively parse the following code as a block, and if
5146 * it contains statements that cannot be members, parse as a block,
5147 * - otherwise, don't parse as a block.
5148 *
5149 * @param unclosedParameterList whether there was a serious problem in the
5150 * parameters list
5151 * @return true if and only if the following code should be parsed as a block.
5152 */
5153 private boolean openingBraceMissing(boolean unclosedParameterList) {
5154 skip(false, true, !unclosedParameterList, !unclosedParameterList);
5155
5156 if (token.kind == LBRACE) {
5157 return true;
5158 } else if (unclosedParameterList) {
5159 return false;
5160 } else {
5161 return switch (token.kind) {
5162 //definitelly sees a statement:
5163 case CASE, DEFAULT, IF, FOR, WHILE, DO, TRY, SWITCH,
5164 RETURN, THROW, BREAK, CONTINUE, ELSE, FINALLY,
5165 CATCH, THIS, SUPER, NEW -> true;
5166 case RBRACE -> {
5167 //check if adding an opening brace would balance out
5168 //the opening and closing braces:
5169 int braceBalance = 1;
5170 VirtualScanner virtualScanner = new VirtualScanner(S);
5171
5172 virtualScanner.nextToken();
5173
5174 while (virtualScanner.token().kind != TokenKind.EOF) {
5175 switch (virtualScanner.token().kind) {
5176 case LBRACE -> braceBalance++;
5177 case RBRACE -> braceBalance--;
5178 }
5179 virtualScanner.nextToken();
5180 }
5181
5182 yield braceBalance == 0;
5183 }
5184 default -> {
5185 //speculatively try to parse as a block, and check
5186 //if the result would suggest there is a block
5187 //e.g.: it contains a statement that is not
5188 //a member declaration
5189 JavacParser speculative = new VirtualParser(this);
5190 JCBlock speculativeResult =
5191 speculative.block();
5192 if (!speculativeResult.stats.isEmpty()) {
5193 JCStatement last = speculativeResult.stats.last();
5194 yield !speculativeResult.stats.stream().allMatch(s -> s.hasTag(VARDEF) ||
5195 s.hasTag(CLASSDEF) ||
5196 s.hasTag(BLOCK) ||
5197 s == last) ||
5198 !(last instanceof JCExpressionStatement exprStatement &&
5199 exprStatement.expr.hasTag(ERRONEOUS));
5200 } else {
5201 yield false;
5202 }
5203 }
5204 };
5205 }
5206 }
5207
5208 /** QualidentList = [Annotations] Qualident {"," [Annotations] Qualident}
5209 */
5210 List<JCExpression> qualidentList(boolean allowAnnos) {
5211 ListBuffer<JCExpression> ts = new ListBuffer<>();
5212
5213 List<JCAnnotation> typeAnnos = allowAnnos ? typeAnnotationsOpt() : List.nil();
5214 JCExpression qi = qualident(allowAnnos);
5215 if (!typeAnnos.isEmpty()) {
5216 JCExpression at = insertAnnotationsToMostInner(qi, typeAnnos, false);
5217 ts.append(at);
5218 } else {
5219 ts.append(qi);
5220 }
5221 while (token.kind == COMMA) {
5222 nextToken();
5223
5224 typeAnnos = allowAnnos ? typeAnnotationsOpt() : List.nil();
5225 qi = qualident(allowAnnos);
5226 if (!typeAnnos.isEmpty()) {
5227 JCExpression at = insertAnnotationsToMostInner(qi, typeAnnos, false);
5228 ts.append(at);
5229 } else {
5230 ts.append(qi);
5231 }
5232 }
5233 return ts.toList();
5234 }
5235
5236 /**
5237 * {@literal
5238 * TypeParametersOpt = ["<" TypeParameter {"," TypeParameter} ">"]
5239 * }
5240 */
5241 protected List<JCTypeParameter> typeParametersOpt() {
5242 return typeParametersOpt(false);
5243 }
5244 /** Parses a potentially empty type parameter list if needed with `allowEmpty`.
5245 * The caller is free to choose the desirable error message in this (erroneous) case.
5246 */
5247 protected List<JCTypeParameter> typeParametersOpt(boolean parseEmpty) {
5248 if (token.kind == LT) {
5249 ListBuffer<JCTypeParameter> typarams = new ListBuffer<>();
5250 nextToken();
5251
5252 if (parseEmpty && token.kind == GT) {
5253 accept(GT);
5254 return null;
5255 }
5256
5257 typarams.append(typeParameter());
5258 while (token.kind == COMMA) {
5259 nextToken();
5260 typarams.append(typeParameter());
5261 }
5262 accept(GT);
5263 return typarams.toList();
5264 } else {
5265 return List.nil();
5266 }
5267 }
5268
5269 /**
5270 * {@literal
5271 * TypeParameter = [Annotations] TypeVariable [TypeParameterBound]
5272 * TypeParameterBound = EXTENDS Type {"&" Type}
5273 * TypeVariable = Ident
5274 * }
5275 */
5276 JCTypeParameter typeParameter() {
5277 int pos = token.pos;
5278 List<JCAnnotation> annos = typeAnnotationsOpt();
5279 Name name = typeName();
5280 ListBuffer<JCExpression> bounds = new ListBuffer<>();
5281 if (token.kind == EXTENDS) {
5282 nextToken();
5283 bounds.append(parseType());
5284 while (token.kind == AMP) {
5285 nextToken();
5286 bounds.append(parseType());
5287 }
5288 }
5289 return toP(F.at(pos).TypeParameter(name, bounds.toList(), annos));
5290 }
5291
5292 /** FormalParameters = "(" [ FormalParameterList ] ")"
5293 * FormalParameterList = [ FormalParameterListNovarargs , ] LastFormalParameter
5294 * FormalParameterListNovarargs = [ FormalParameterListNovarargs , ] FormalParameter
5295 */
5296 List<JCVariableDecl> formalParameters() {
5297 return formalParameters(false, false);
5298 }
5299 List<JCVariableDecl> formalParameters(boolean lambdaParameters, boolean recordComponents) {
5300 ListBuffer<JCVariableDecl> params = new ListBuffer<>();
5301 JCVariableDecl lastParam;
5302 accept(LPAREN);
5303 if (token.kind != RPAREN) {
5304 this.allowThisIdent = !lambdaParameters && !recordComponents;
5305 lastParam = formalParameter(lambdaParameters, recordComponents);
5306 if (lastParam.nameexpr != null) {
5307 this.receiverParam = lastParam;
5308 } else {
5309 params.append(lastParam);
5310 }
5311 this.allowThisIdent = false;
5312 while (token.kind == COMMA) {
5313 if ((lastParam.mods.flags & Flags.VARARGS) != 0) {
5314 log.error(DiagnosticFlag.SYNTAX, lastParam, Errors.VarargsMustBeLast);
5315 }
5316 nextToken();
5317 params.append(lastParam = formalParameter(lambdaParameters, recordComponents));
5318 }
5319 }
5320 if (token.kind == RPAREN) {
5321 nextToken();
5322 } else {
5323 setErrorEndPos(token.pos);
5324 reportSyntaxError(S.prevToken().endPos, Errors.Expected3(COMMA, RPAREN, LBRACKET));
5325 }
5326 return params.toList();
5327 }
5328
5329 List<JCVariableDecl> implicitParameters(boolean hasParens) {
5330 if (hasParens) {
5331 accept(LPAREN);
5332 }
5333 ListBuffer<JCVariableDecl> params = new ListBuffer<>();
5334 if (token.kind != RPAREN && token.kind != ARROW) {
5335 params.append(implicitParameter());
5336 while (token.kind == COMMA) {
5337 nextToken();
5338 params.append(implicitParameter());
5339 }
5340 }
5341 if (hasParens) {
5342 accept(RPAREN);
5343 }
5344 return params.toList();
5345 }
5346
5347 JCModifiers optFinal(long flags) {
5348 JCModifiers mods = modifiersOpt();
5349 checkNoMods(mods.flags & ~(Flags.FINAL | Flags.DEPRECATED));
5350 mods.flags |= flags;
5351 return mods;
5352 }
5353
5354 /**
5355 * Inserts the annotations (and possibly a new array level)
5356 * to the left-most type in an array or nested type.
5357 *
5358 * When parsing a type like {@code @B Outer.Inner @A []}, the
5359 * {@code @A} annotation should target the array itself, while
5360 * {@code @B} targets the nested type {@code Outer}.
5361 *
5362 * Currently the parser parses the annotation first, then
5363 * the array, and then inserts the annotation to the left-most
5364 * nested type.
5365 *
5366 * When {@code createNewLevel} is true, then a new array
5367 * level is inserted as the most inner type, and have the
5368 * annotations target it. This is useful in the case of
5369 * varargs, e.g. {@code String @A [] @B ...}, as the parser
5370 * first parses the type {@code String @A []} then inserts
5371 * a new array level with {@code @B} annotation.
5372 */
5373 private JCExpression insertAnnotationsToMostInner(
5374 JCExpression type, List<JCAnnotation> annos,
5375 boolean createNewLevel) {
5376 int origEndPos = getEndPos(type);
5377 JCExpression mostInnerType = type;
5378 JCArrayTypeTree mostInnerArrayType = null;
5379 while (TreeInfo.typeIn(mostInnerType).hasTag(TYPEARRAY)) {
5380 mostInnerArrayType = (JCArrayTypeTree) TreeInfo.typeIn(mostInnerType);
5381 mostInnerType = mostInnerArrayType.elemtype;
5382 }
5383
5384 if (createNewLevel) {
5385 mostInnerType = to(F.at(token.pos).TypeArray(mostInnerType));
5386 origEndPos = getEndPos(mostInnerType);
5387 }
5388
5389 JCExpression mostInnerTypeToReturn = mostInnerType;
5390 if (annos.nonEmpty()) {
5391 JCExpression lastToModify = mostInnerType;
5392
5393 while (TreeInfo.typeIn(mostInnerType).hasTag(SELECT) ||
5394 TreeInfo.typeIn(mostInnerType).hasTag(TYPEAPPLY)) {
5395 while (TreeInfo.typeIn(mostInnerType).hasTag(SELECT)) {
5396 lastToModify = mostInnerType;
5397 mostInnerType = ((JCFieldAccess) TreeInfo.typeIn(mostInnerType)).getExpression();
5398 }
5399 while (TreeInfo.typeIn(mostInnerType).hasTag(TYPEAPPLY)) {
5400 lastToModify = mostInnerType;
5401 mostInnerType = ((JCTypeApply) TreeInfo.typeIn(mostInnerType)).clazz;
5402 }
5403 }
5404
5405 mostInnerType = F.at(annos.head.pos).AnnotatedType(annos, mostInnerType);
5406
5407 if (TreeInfo.typeIn(lastToModify).hasTag(TYPEAPPLY)) {
5408 ((JCTypeApply) TreeInfo.typeIn(lastToModify)).clazz = mostInnerType;
5409 } else if (TreeInfo.typeIn(lastToModify).hasTag(SELECT)) {
5410 ((JCFieldAccess) TreeInfo.typeIn(lastToModify)).selected = mostInnerType;
5411 } else {
5412 // We never saw a SELECT or TYPEAPPLY, return the annotated type.
5413 mostInnerTypeToReturn = mostInnerType;
5414 }
5415 }
5416
5417 if (mostInnerArrayType == null) {
5418 return mostInnerTypeToReturn;
5419 } else {
5420 mostInnerArrayType.elemtype = mostInnerTypeToReturn;
5421 return storeEnd(type, origEndPos);
5422 }
5423 }
5424
5425 /** FormalParameter = { FINAL | '@' Annotation } Type VariableDeclaratorId
5426 * LastFormalParameter = { FINAL | '@' Annotation } Type '...' Ident | FormalParameter
5427 */
5428 protected JCVariableDecl formalParameter(boolean lambdaParameter, boolean recordComponent) {
5429 JCModifiers mods = !recordComponent ? optFinal(Flags.PARAMETER) : modifiersOpt();
5430 if (recordComponent && mods.flags != 0) {
5431 log.error(mods.pos, Errors.RecordCantDeclareFieldModifiers);
5432 }
5433 if (recordComponent) {
5434 mods.flags |= Flags.RECORD | Flags.FINAL | Flags.PRIVATE | Flags.GENERATED_MEMBER;
5435 }
5436 // need to distinguish between vararg annos and array annos
5437 // look at typeAnnotationsPushedBack comment
5438 this.permitTypeAnnotationsPushBack = true;
5439 JCExpression type = parseType(lambdaParameter);
5440 this.permitTypeAnnotationsPushBack = false;
5441
5442 if (token.kind == ELLIPSIS) {
5443 List<JCAnnotation> varargsAnnos = typeAnnotationsPushedBack;
5444 typeAnnotationsPushedBack = List.nil();
5445 mods.flags |= Flags.VARARGS;
5446 // insert var arg type annotations
5447 type = insertAnnotationsToMostInner(type, varargsAnnos, true);
5448 nextToken();
5449 } else {
5450 // if not a var arg, then typeAnnotationsPushedBack should be null
5451 if (typeAnnotationsPushedBack.nonEmpty()) {
5452 reportSyntaxError(typeAnnotationsPushedBack.head.pos, Errors.IllegalStartOfType);
5453 }
5454 typeAnnotationsPushedBack = List.nil();
5455 }
5456 return variableDeclaratorId(mods, type, false, lambdaParameter, recordComponent);
5457 }
5458
5459 protected JCVariableDecl implicitParameter() {
5460 JCModifiers mods = F.at(token.pos).Modifiers(Flags.PARAMETER);
5461 return variableDeclaratorId(mods, null, false, true, false);
5462 }
5463
5464 /* ---------- auxiliary methods -------------- */
5465 /** Check that given tree is a legal expression statement.
5466 */
5467 protected JCExpression checkExprStat(JCExpression t) {
5468 if (!TreeInfo.isExpressionStatement(t)) {
5469 JCExpression ret = F.at(t.pos).Erroneous(List.<JCTree>of(t));
5470 log.error(DiagnosticFlag.SYNTAX, ret, Errors.NotStmt);
5471 return ret;
5472 } else {
5473 return t;
5474 }
5475 }
5476
5477 /** Return precedence of operator represented by token,
5478 * -1 if token is not a binary operator. @see TreeInfo.opPrec
5479 */
5480 static int prec(TokenKind token) {
5481 JCTree.Tag oc = optag(token);
5482 return (oc != NO_TAG) ? TreeInfo.opPrec(oc) : -1;
5483 }
5484
5485 /**
5486 * Return the lesser of two positions, making allowance for either one
5487 * being unset.
5488 */
5489 static int earlier(int pos1, int pos2) {
5490 if (pos1 == Position.NOPOS)
5491 return pos2;
5492 if (pos2 == Position.NOPOS)
5493 return pos1;
5494 return (pos1 < pos2 ? pos1 : pos2);
5495 }
5496
5497 /** Return operation tag of binary operator represented by token,
5498 * No_TAG if token is not a binary operator.
5499 */
5500 static JCTree.Tag optag(TokenKind token) {
5501 switch (token) {
5502 case BARBAR:
5503 return OR;
5504 case AMPAMP:
5505 return AND;
5506 case BAR:
5507 return BITOR;
5508 case BAREQ:
5509 return BITOR_ASG;
5510 case CARET:
5511 return BITXOR;
5512 case CARETEQ:
5513 return BITXOR_ASG;
5514 case AMP:
5515 return BITAND;
5516 case AMPEQ:
5517 return BITAND_ASG;
5518 case EQEQ:
5519 return JCTree.Tag.EQ;
5520 case BANGEQ:
5521 return NE;
5522 case LT:
5523 return JCTree.Tag.LT;
5524 case GT:
5525 return JCTree.Tag.GT;
5526 case LTEQ:
5527 return LE;
5528 case GTEQ:
5529 return GE;
5530 case LTLT:
5531 return SL;
5532 case LTLTEQ:
5533 return SL_ASG;
5534 case GTGT:
5535 return SR;
5536 case GTGTEQ:
5537 return SR_ASG;
5538 case GTGTGT:
5539 return USR;
5540 case GTGTGTEQ:
5541 return USR_ASG;
5542 case PLUS:
5543 return JCTree.Tag.PLUS;
5544 case PLUSEQ:
5545 return PLUS_ASG;
5546 case SUB:
5547 return MINUS;
5548 case SUBEQ:
5549 return MINUS_ASG;
5550 case STAR:
5551 return MUL;
5552 case STAREQ:
5553 return MUL_ASG;
5554 case SLASH:
5555 return DIV;
5556 case SLASHEQ:
5557 return DIV_ASG;
5558 case PERCENT:
5559 return MOD;
5560 case PERCENTEQ:
5561 return MOD_ASG;
5562 case INSTANCEOF:
5563 return TYPETEST;
5564 default:
5565 return NO_TAG;
5566 }
5567 }
5568
5569 /** Return operation tag of unary operator represented by token,
5570 * No_TAG if token is not a binary operator.
5571 */
5572 static JCTree.Tag unoptag(TokenKind token) {
5573 switch (token) {
5574 case PLUS:
5575 return POS;
5576 case SUB:
5577 return NEG;
5578 case BANG:
5579 return NOT;
5580 case TILDE:
5581 return COMPL;
5582 case PLUSPLUS:
5583 return PREINC;
5584 case SUBSUB:
5585 return PREDEC;
5586 default:
5587 return NO_TAG;
5588 }
5589 }
5590
5591 /** Return type tag of basic type represented by token,
5592 * NONE if token is not a basic type identifier.
5593 */
5594 static TypeTag typetag(TokenKind token) {
5595 switch (token) {
5596 case BYTE:
5597 return TypeTag.BYTE;
5598 case CHAR:
5599 return TypeTag.CHAR;
5600 case SHORT:
5601 return TypeTag.SHORT;
5602 case INT:
5603 return TypeTag.INT;
5604 case LONG:
5605 return TypeTag.LONG;
5606 case FLOAT:
5607 return TypeTag.FLOAT;
5608 case DOUBLE:
5609 return TypeTag.DOUBLE;
5610 case BOOLEAN:
5611 return TypeTag.BOOLEAN;
5612 default:
5613 return TypeTag.NONE;
5614 }
5615 }
5616
5617 void checkSourceLevel(Feature feature) {
5618 checkSourceLevel(token.pos, feature);
5619 }
5620
5621 protected void checkSourceLevel(int pos, Feature feature) {
5622 if (preview.isPreview(feature) && !preview.isEnabled()) {
5623 //preview feature without --preview flag, error
5624 log.error(pos, preview.disabledError(feature));
5625 } else if (!feature.allowedInSource(source)) {
5626 //incompatible source level, error
5627 log.error(pos, feature.error(source.name));
5628 } else if (preview.isPreview(feature)) {
5629 //use of preview feature, warn
5630 preview.warnPreview(pos, feature);
5631 }
5632 }
5633
5634 private void updateUnexpectedTopLevelDefinitionStartError(boolean hasPackageDecl) {
5635 //TODO: proper tests for this logic (and updates):
5636 if (parseModuleInfo) {
5637 unexpectedTopLevelDefinitionStartError = Errors.ExpectedModuleOrOpen;
5638 } else if (Feature.IMPLICIT_CLASSES.allowedInSource(source) && !hasPackageDecl) {
5639 unexpectedTopLevelDefinitionStartError = Errors.ClassMethodOrFieldExpected;
5640 } else if (allowRecords) {
5641 unexpectedTopLevelDefinitionStartError = Errors.Expected4(CLASS, INTERFACE, ENUM, "record");
5642 } else {
5643 unexpectedTopLevelDefinitionStartError = Errors.Expected3(CLASS, INTERFACE, ENUM);
5644 }
5645 }
5646
5647 /**
5648 * A straightforward {@link EndPosTable} implementation.
5649 */
5650 protected static class SimpleEndPosTable extends AbstractEndPosTable {
5651
5652 private final IntHashTable endPosMap = new IntHashTable();
5653
5654 @Override
5655 public <T extends JCTree> T storeEnd(T tree, int endpos) {
5656 endPosMap.put(tree, Math.max(endpos, errorEndPos));
5657 return tree;
5658 }
5659
5660 @Override
5661 public int getEndPos(JCTree tree) {
5662 int value = endPosMap.get(tree);
5663 // As long as Position.NOPOS==-1, this just returns value.
5664 return (value == -1) ? Position.NOPOS : value;
5665 }
5666
5667 @Override
5668 public int replaceTree(JCTree oldTree, JCTree newTree) {
5669 int pos = endPosMap.remove(oldTree);
5670 if (pos != -1 && newTree != null) {
5671 storeEnd(newTree, pos);
5672 }
5673 return pos;
5674 }
5675 }
5676
5677 /**
5678 * A minimal implementation that only stores what's required.
5679 */
5680 protected static class MinimalEndPosTable extends SimpleEndPosTable {
5681
5682 @Override
5683 public <T extends JCTree> T storeEnd(T tree, int endpos) {
5684 switch (tree.getTag()) {
5685 case MODULEDEF:
5686 case PACKAGEDEF:
5687 case CLASSDEF:
5688 case METHODDEF:
5689 case VARDEF:
5690 break;
5691 default:
5692 return tree;
5693 }
5694 return super.storeEnd(tree, endpos);
5695 }
5696 }
5697
5698 protected abstract static class AbstractEndPosTable implements EndPosTable {
5699
5700 /**
5701 * Store the last error position.
5702 */
5703 public int errorEndPos = Position.NOPOS;
5704
5705 @Override
5706 public void setErrorEndPos(int errPos) {
5707 if (errPos > errorEndPos) {
5708 errorEndPos = errPos;
5709 }
5710 }
5711 }
5712 }