< prev index next > src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java
Print this page
import com.sun.source.tree.CaseTree;
import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
import com.sun.source.tree.ModuleTree.ModuleKind;
import com.sun.tools.javac.code.*;
+ import com.sun.tools.javac.code.Flags.Flag;
import com.sun.tools.javac.code.Source.Feature;
import com.sun.tools.javac.file.PathFileObject;
import com.sun.tools.javac.parser.Tokens.*;
+ import com.sun.tools.javac.parser.Tokens.Comment.CommentStyle;
import com.sun.tools.javac.resources.CompilerProperties.Errors;
import com.sun.tools.javac.resources.CompilerProperties.Fragments;
import com.sun.tools.javac.resources.CompilerProperties.Warnings;
import com.sun.tools.javac.tree.*;
import com.sun.tools.javac.tree.JCTree.*;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag;
import com.sun.tools.javac.util.JCDiagnostic.Error;
import com.sun.tools.javac.util.JCDiagnostic.Fragment;
import com.sun.tools.javac.util.List;
+ import static com.sun.tools.javac.code.Flags.asFlagSet;
import static com.sun.tools.javac.parser.Tokens.TokenKind.*;
import static com.sun.tools.javac.parser.Tokens.TokenKind.ASSERT;
import static com.sun.tools.javac.parser.Tokens.TokenKind.CASE;
import static com.sun.tools.javac.parser.Tokens.TokenKind.CATCH;
import static com.sun.tools.javac.parser.Tokens.TokenKind.EQ;
import static com.sun.tools.javac.parser.Tokens.TokenKind.GT;
import static com.sun.tools.javac.parser.Tokens.TokenKind.IMPORT;
import static com.sun.tools.javac.parser.Tokens.TokenKind.LT;
+ import static com.sun.tools.javac.parser.Tokens.TokenKind.SYNCHRONIZED;
import com.sun.tools.javac.parser.VirtualParser.VirtualScanner;
import static com.sun.tools.javac.tree.JCTree.Tag.*;
import static com.sun.tools.javac.resources.CompilerProperties.Fragments.ImplicitAndExplicitNotAllowed;
import static com.sun.tools.javac.resources.CompilerProperties.Fragments.VarAndExplicitNotAllowed;
import static com.sun.tools.javac.resources.CompilerProperties.Fragments.VarAndImplicitNotAllowed;
this.errorTree = F.Erroneous();
this.endPosTable = newEndPosTable(keepEndPositions);
this.allowYieldStatement = Feature.SWITCH_EXPRESSION.allowedInSource(source);
this.allowRecords = Feature.RECORDS.allowedInSource(source);
this.allowSealedTypes = Feature.SEALED_CLASSES.allowedInSource(source);
+ this.allowValueClasses = (!preview.isPreview(Feature.VALUE_CLASSES) || preview.isEnabled()) &&
+ Feature.VALUE_CLASSES.allowedInSource(source);
}
/** Construct a parser from an existing parser, with minimal overhead.
*/
@SuppressWarnings("this-escape")
this.errorTree = F.Erroneous();
this.endPosTable = newEndPosTable(false);
this.allowYieldStatement = Feature.SWITCH_EXPRESSION.allowedInSource(source);
this.allowRecords = Feature.RECORDS.allowedInSource(source);
this.allowSealedTypes = Feature.SEALED_CLASSES.allowedInSource(source);
+ this.allowValueClasses = (!preview.isPreview(Feature.VALUE_CLASSES) || preview.isEnabled()) &&
+ Feature.VALUE_CLASSES.allowedInSource(source);
}
protected AbstractEndPosTable newEndPosTable(boolean keepEndPositions) {
return keepEndPositions
? new SimpleEndPosTable(this)
/** Switch: are records allowed in this source level?
*/
boolean allowRecords;
+ /** Switch: are value classes allowed in this source level?
+ */
+ boolean allowValueClasses;
+
/** Switch: are sealed types allowed in this source level?
*/
boolean allowSealedTypes;
/** The type of the method receiver, as specified by a first "this" parameter.
// Don't return here -- error recovery attempt
illegal(annos.head.pos);
}
break loop;
case LT:
- if (!isMode(TYPE) && isUnboundMemberRef()) {
- //this is an unbound method reference whose qualifier
+ if (!isMode(TYPE) && isParameterizedTypePrefix()) {
+ //this is either an unbound method reference whose qualifier
//is a generic type i.e. A<S>::m
int pos1 = token.pos;
accept(LT);
ListBuffer<JCExpression> args = new ListBuffer<>();
args.append(typeArgument());
* If we see an identifier followed by a '<' it could be an unbound
* method reference or a binary expression. To disambiguate, look for a
* matching '>' and see if the subsequent terminal is either '.' or '::'.
*/
@SuppressWarnings("fallthrough")
- boolean isUnboundMemberRef() {
+ boolean isParameterizedTypePrefix() {
int pos = 0, depth = 0;
outer: for (Token t = S.token(pos) ; ; t = S.token(++pos)) {
switch (t.kind) {
case IDENTIFIER: case UNDERSCORE: case QUES: case EXTENDS: case SUPER:
case DOT: case RBRACKET: case LBRACKET: case COMMA:
nextToken();
return List.of(classOrRecordOrInterfaceOrEnumDeclaration(modifiersOpt(), token.docComment()));
}
}
}
+ if ((isValueModifier()) && allowValueClasses) {
+ checkSourceLevel(Feature.VALUE_CLASSES);
+ dc = token.docComment();
+ return List.of(classOrRecordOrInterfaceOrEnumDeclaration(modifiersOpt(), dc));
+ }
dc = token.docComment();
if (isRecordStart() && allowRecords) {
return List.of(recordDeclaration(F.at(pos).Modifiers(0), dc));
} else {
Token prevToken = token;
if (isSealedClassStart(false)) {
checkSourceLevel(Feature.SEALED_CLASSES);
flag = Flags.SEALED;
break;
}
+ if (isValueModifier()) {
+ checkSourceLevel(Feature.VALUE_CLASSES);
+ flag = Flags.VALUE_CLASS;
+ break;
+ }
break loop;
}
default: break loop;
}
if ((flags & flag) != 0) log.error(DiagnosticFlag.SYNTAX, token.pos, Errors.RepeatedModifier);
return Source.JDK14;
} else if (shouldWarn) {
log.warning(pos, Warnings.RestrictedTypeNotAllowedPreview(name, Source.JDK14));
}
}
+ if (name == names.value) {
+ if (allowValueClasses) {
+ return Source.JDK23;
+ } else if (shouldWarn) {
+ log.warning(pos, Warnings.RestrictedTypeNotAllowedPreview(name, Source.JDK23));
+ }
+ }
if (name == names.sealed) {
if (allowSealedTypes) {
return Source.JDK15;
} else if (shouldWarn) {
log.warning(pos, Warnings.RestrictedTypeNotAllowedPreview(name, Source.JDK15));
}
}
return false;
}
+ protected boolean isValueModifier() {
+ if (token.kind == IDENTIFIER && token.name() == names.value) {
+ boolean isValueModifier = false;
+ Token next = S.token(1);
+ switch (next.kind) {
+ case PRIVATE: case PROTECTED: case PUBLIC: case STATIC: case TRANSIENT:
+ case FINAL: case ABSTRACT: case NATIVE: case VOLATILE: case SYNCHRONIZED:
+ case STRICTFP: case MONKEYS_AT: case DEFAULT: case BYTE: case SHORT:
+ case CHAR: case INT: case LONG: case FLOAT: case DOUBLE: case BOOLEAN: case VOID:
+ case CLASS: case INTERFACE: case ENUM:
+ isValueModifier = true;
+ break;
+ case IDENTIFIER: // value record R || value value || new value Comparable() {} ??
+ if (next.name() == names.record || next.name() == names.value
+ || (mode & EXPR) != 0)
+ isValueModifier = true;
+ break;
+ }
+ if (isValueModifier) {
+ checkSourceLevel(Feature.VALUE_CLASSES);
+ return true;
+ }
+ }
+ return false;
+ }
+
protected boolean isSealedClassStart(boolean local) {
if (token.name() == names.sealed) {
Token next = S.token(1);
if (allowedAfterSealedOrNonSealed(next, local, false)) {
checkSourceLevel(Feature.SEALED_CLASSES);
case MONKEYS_AT -> {
Token afterNext = S.token(2);
yield afterNext.kind != INTERFACE || currentIsNonSealed;
}
case PUBLIC, PROTECTED, PRIVATE, ABSTRACT, STATIC, FINAL, STRICTFP, CLASS, INTERFACE, ENUM -> true;
- case IDENTIFIER -> isNonSealedIdentifier(next, currentIsNonSealed ? 3 : 1) || next.name() == names.sealed;
+ case IDENTIFIER -> isNonSealedIdentifier(next, currentIsNonSealed ? 3 : 1) ||
+ next.name() == names.sealed ||
+ allowValueClasses && next.name() == names.value;
default -> false;
};
}
/** MethodDeclaratorRest =
< prev index next >