< 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.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 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;
import com.sun.tools.javac.util.JCDiagnostic.SimpleDiagnosticPosition;
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.allowPrimitiveClasses = Feature.PRIMITIVE_CLASSES.allowedInSource(source) && fac.options.isSet("enablePrimitiveClasses");
+ this.allowValueClasses = 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.allowPrimitiveClasses = parser.allowPrimitiveClasses;
+ this.allowValueClasses = parser.allowValueClasses;
}
protected AbstractEndPosTable newEndPosTable(boolean keepEndPositions) {
return keepEndPositions
? new SimpleEndPosTable(this)
/** Switch: are records allowed in this source level?
*/
boolean allowRecords;
+ /** Switch: are primitive classes allowed in this source level?
+ */
+ boolean allowPrimitiveClasses;
+
+ /** 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.
setErrorEndPos(token.pos);
reportSyntaxError(S.prevToken().endPos, errorProvider.apply(tk));
}
}
+ /** If next input token matches one of the two given tokens, skip it, otherwise report
+ * an error.
+ *
+ * @return The actual token kind.
+ */
+ public TokenKind accept2(TokenKind tk1, TokenKind tk2) {
+ TokenKind returnValue = token.kind;
+ if (token.kind == tk1 || token.kind == tk2) {
+ nextToken();
+ } else {
+ setErrorEndPos(token.pos);
+ reportSyntaxError(S.prevToken().endPos, Errors.Expected2(tk1, tk2));
+ }
+ return returnValue;
+ }
+
/** Report an illegal start of expression/type error at given position.
*/
JCExpression illegal(int pos) {
setErrorEndPos(pos);
if (isMode(EXPR))
setMode(mode & ~NOPARAMS);
typeArgs = typeArgumentsOpt(EXPR);
setMode(prevmode);
if (isMode(EXPR)) {
switch (token.kind) {
+ case DEFAULT:
+ if (typeArgs != null) return illegal();
+ selectExprMode();
+ t = to(F.at(pos).DefaultValue(t));
+ nextToken();
+ break loop;
case CLASS:
if (typeArgs != null) return illegal();
selectExprMode();
t = to(F.at(pos).Select(t, names._class));
nextToken();
// 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
! //is a generic type i.e. A<S>::m
int pos1 = token.pos;
accept(LT);
ListBuffer<JCExpression> args = new ListBuffer<>();
args.append(typeArgument());
while (token.kind == COMMA) {
// Don't return here -- error recovery attempt
illegal(annos.head.pos);
}
break loop;
case LT:
! if (!isMode(TYPE) && isParameterizedTypePrefix()) {
! //this is either an unbound method reference whose qualifier
! //is a generic type i.e. A<S>::m or a default value creation of
+ //the form ValueType<S>.default
int pos1 = token.pos;
accept(LT);
ListBuffer<JCExpression> args = new ListBuffer<>();
args.append(typeArgument());
while (token.kind == COMMA) {
}
accept(GT);
t = toP(F.at(pos1).TypeApply(t, args.toList()));
while (token.kind == DOT) {
nextToken();
+ if (token.kind == DEFAULT) {
+ t = toP(F.at(token.pos).DefaultValue(t));
+ nextToken();
+ selectExprMode();
+ return term3Rest(t, typeArgs);
+ }
selectTypeMode();
t = toP(F.at(token.pos).Select(t, ident()));
t = typeArgumentsOpt(t);
}
t = bracketsOpt(t);
return toP(t);
}
/**
* 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() {
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:
return toP(t);
}
/**
* If we see an identifier followed by a '<' it could be an unbound
! * method reference or a default value creation that uses a parameterized type
+ * or a binary expression. To disambiguate, look for a
* matching '>' and see if the subsequent terminal is either '.' or '::'.
*/
@SuppressWarnings("fallthrough")
! 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:
JCExpression bracketsSuffix(JCExpression t) {
if (isMode(EXPR) && token.kind == DOT) {
selectExprMode();
int pos = token.pos;
nextToken();
! accept(CLASS);
if (token.pos == endPosTable.errorEndPos) {
// error recovery
Name name;
if (LAX_IDENTIFIER.test(token.kind)) {
name = token.name();
JCExpression bracketsSuffix(JCExpression t) {
if (isMode(EXPR) && token.kind == DOT) {
selectExprMode();
int pos = token.pos;
nextToken();
! TokenKind selector = accept2(CLASS, DEFAULT);
if (token.pos == endPosTable.errorEndPos) {
// error recovery
Name name;
if (LAX_IDENTIFIER.test(token.kind)) {
name = token.name();
// Type annotations are illegal on class literals. Annotated non array class literals
// are complained about directly in term3(), Here check for type annotations on dimensions
// taking care to handle some interior dimension(s) being annotated.
if ((tag == TYPEARRAY && TreeInfo.containsTypeAnnotation(t)) || tag == ANNOTATED_TYPE)
syntaxError(token.pos, Errors.NoAnnotationsOnDotClass);
! t = toP(F.at(pos).Select(t, names._class));
}
} else if (isMode(TYPE)) {
if (token.kind != COLCOL) {
selectTypeMode();
}
// Type annotations are illegal on class literals. Annotated non array class literals
// are complained about directly in term3(), Here check for type annotations on dimensions
// taking care to handle some interior dimension(s) being annotated.
if ((tag == TYPEARRAY && TreeInfo.containsTypeAnnotation(t)) || tag == ANNOTATED_TYPE)
syntaxError(token.pos, Errors.NoAnnotationsOnDotClass);
! if (selector == CLASS) {
+ t = toP(F.at(pos).Select(t, names._class));
+ } else {
+ t = toP(F.at(pos).DefaultValue(t));
+ }
}
} else if (isMode(TYPE)) {
if (token.kind != COLCOL) {
selectTypeMode();
}
}
Name refName;
ReferenceMode refMode;
if (token.kind == NEW) {
refMode = ReferenceMode.NEW;
+ // TODO - will be converted in Attr
refName = names.init;
nextToken();
} else {
refMode = ReferenceMode.INVOKE;
refName = ident();
}
/** Creator = [Annotations] Qualident [TypeArguments] ( ArrayCreatorRest | ClassCreatorRest )
*/
JCExpression creator(int newpos, List<JCExpression> typeArgs) {
! List<JCAnnotation> newAnnotations = typeAnnotationsOpt();
!
switch (token.kind) {
case BYTE: case SHORT: case CHAR: case INT: case LONG: case FLOAT:
case DOUBLE: case BOOLEAN:
if (typeArgs == null) {
if (newAnnotations.isEmpty()) {
return arrayCreatorRest(newpos, basicType());
} else {
return arrayCreatorRest(newpos, toP(F.at(newAnnotations.head.pos).AnnotatedType(newAnnotations, basicType())));
}
/** Creator = [Annotations] Qualident [TypeArguments] ( ArrayCreatorRest | ClassCreatorRest )
*/
JCExpression creator(int newpos, List<JCExpression> typeArgs) {
! final JCModifiers mods = modifiersOpt();
! List<JCAnnotation> newAnnotations = mods.annotations;
switch (token.kind) {
case BYTE: case SHORT: case CHAR: case INT: case LONG: case FLOAT:
case DOUBLE: case BOOLEAN:
+ if (mods.flags != 0) {
+ log.error(token.pos, Errors.ModNotAllowedHere(asFlagSet(mods.flags)));
+ }
if (typeArgs == null) {
if (newAnnotations.isEmpty()) {
return arrayCreatorRest(newpos, basicType());
} else {
return arrayCreatorRest(newpos, toP(F.at(newAnnotations.head.pos).AnnotatedType(newAnnotations, basicType())));
reportSyntaxError(err, Errors.CannotCreateArrayWithTypeArguments);
return toP(err);
}
return e;
} else if (token.kind == LPAREN) {
// handle type annotations for instantiations and anonymous classes
if (newAnnotations.nonEmpty()) {
t = insertAnnotationsToMostInner(t, newAnnotations, false);
}
! return classCreatorRest(newpos, null, typeArgs, t);
} else {
setErrorEndPos(token.pos);
reportSyntaxError(token.pos, Errors.Expected2(LPAREN, LBRACKET));
t = toP(F.at(newpos).NewClass(null, typeArgs, t, List.nil(), null));
return toP(F.at(newpos).Erroneous(List.<JCTree>of(t)));
reportSyntaxError(err, Errors.CannotCreateArrayWithTypeArguments);
return toP(err);
}
return e;
} else if (token.kind == LPAREN) {
+ long badModifiers = mods.flags & ~(Flags.PRIMITIVE_CLASS | Flags.VALUE_CLASS | Flags.FINAL);
+ if (badModifiers != 0)
+ log.error(token.pos, Errors.ModNotAllowedHere(asFlagSet(badModifiers)));
// handle type annotations for instantiations and anonymous classes
if (newAnnotations.nonEmpty()) {
t = insertAnnotationsToMostInner(t, newAnnotations, false);
}
! JCNewClass newClass = classCreatorRest(newpos, null, typeArgs, t, mods.flags);
+ if ((newClass.def == null) && (mods.flags != 0)) {
+ log.error(newClass.pos, Errors.ModNotAllowedHere(asFlagSet(mods.flags)));
+ }
+ return newClass;
} else {
setErrorEndPos(token.pos);
reportSyntaxError(token.pos, Errors.Expected2(LPAREN, LBRACKET));
t = toP(F.at(newpos).NewClass(null, typeArgs, t, List.nil(), null));
return toP(F.at(newpos).Erroneous(List.<JCTree>of(t)));
if (token.kind == LT) {
int prevmode = mode;
t = typeArguments(t, true);
setMode(prevmode);
}
! return classCreatorRest(newpos, encl, typeArgs, t);
}
/** ArrayCreatorRest = [Annotations] "[" ( "]" BracketsOpt ArrayInitializer
* | Expression "]" {[Annotations] "[" Expression "]"} BracketsOpt )
*/
if (token.kind == LT) {
int prevmode = mode;
t = typeArguments(t, true);
setMode(prevmode);
}
! return classCreatorRest(newpos, encl, typeArgs, t, 0);
}
/** ArrayCreatorRest = [Annotations] "[" ( "]" BracketsOpt ArrayInitializer
* | Expression "]" {[Annotations] "[" Expression "]"} BracketsOpt )
*/
/** ClassCreatorRest = Arguments [ClassBody]
*/
JCNewClass classCreatorRest(int newpos,
JCExpression encl,
List<JCExpression> typeArgs,
! JCExpression t)
{
List<JCExpression> args = arguments();
JCClassDecl body = null;
if (token.kind == LBRACE) {
int pos = token.pos;
List<JCTree> defs = classInterfaceOrRecordBody(names.empty, false, false);
! JCModifiers mods = F.at(Position.NOPOS).Modifiers(0);
body = toP(F.at(pos).AnonymousClassDef(mods, defs));
}
! return toP(F.at(newpos).NewClass(encl, typeArgs, t, args, body));
}
/** ArrayInitializer = "{" [VariableInitializer {"," VariableInitializer}] [","] "}"
*/
JCExpression arrayInitializer(int newpos, JCExpression t) {
/** ClassCreatorRest = Arguments [ClassBody]
*/
JCNewClass classCreatorRest(int newpos,
JCExpression encl,
List<JCExpression> typeArgs,
! JCExpression t,
+ long flags)
{
List<JCExpression> args = arguments();
JCClassDecl body = null;
if (token.kind == LBRACE) {
int pos = token.pos;
List<JCTree> defs = classInterfaceOrRecordBody(names.empty, false, false);
! JCModifiers mods = F.at(Position.NOPOS).Modifiers(flags);
body = toP(F.at(pos).AnonymousClassDef(mods, defs));
}
! JCNewClass newClass = toP(F.at(newpos).NewClass(encl, typeArgs, t, args, body));
+ return newClass;
}
/** ArrayInitializer = "{" [VariableInitializer {"," VariableInitializer}] [","] "}"
*/
JCExpression arrayInitializer(int newpos, JCExpression t) {
nextToken();
return List.of(classOrRecordOrInterfaceOrEnumDeclaration(modifiersOpt(), token.comment(CommentStyle.JAVADOC)));
}
}
}
+ if ((isPrimitiveModifier() && allowPrimitiveClasses) || (isValueModifier() || isIdentityModifier()) && allowValueClasses) {
+ dc = token.comment(CommentStyle.JAVADOC);
+ return List.of(classOrRecordOrInterfaceOrEnumDeclaration(modifiersOpt(), dc));
+ }
if (isRecordStart() && allowRecords) {
dc = token.comment(CommentStyle.JAVADOC);
return List.of(recordDeclaration(F.at(pos).Modifiers(0), dc));
} else {
Token prevToken = token;
if (token.kind == FINAL || token.kind == MONKEYS_AT) {
return variableDeclarators(optFinal(0), parseType(true), stats, true).toList();
} else {
JCExpression t = term(EXPR | TYPE);
if (wasTypeMode() && LAX_IDENTIFIER.test(token.kind)) {
! return variableDeclarators(modifiersOpt(), t, stats, true).toList();
} else if (wasTypeMode() && token.kind == COLON) {
log.error(DiagnosticFlag.SYNTAX, pos, Errors.BadInitializer("for-loop"));
return List.of((JCStatement)F.at(pos).VarDef(modifiersOpt(), names.error, t, null));
} else {
return moreStatementExpressions(pos, t, stats).toList();
if (token.kind == FINAL || token.kind == MONKEYS_AT) {
return variableDeclarators(optFinal(0), parseType(true), stats, true).toList();
} else {
JCExpression t = term(EXPR | TYPE);
if (wasTypeMode() && LAX_IDENTIFIER.test(token.kind)) {
! pos = token.pos;
+ JCModifiers mods = F.at(Position.NOPOS).Modifiers(0);
+ F.at(pos);
+ return variableDeclarators(mods, t, stats, true).toList();
} else if (wasTypeMode() && token.kind == COLON) {
log.error(DiagnosticFlag.SYNTAX, pos, Errors.BadInitializer("for-loop"));
return List.of((JCStatement)F.at(pos).VarDef(modifiersOpt(), names.error, t, null));
} else {
return moreStatementExpressions(pos, t, stats).toList();
if (isSealedClassStart(false)) {
checkSourceLevel(Feature.SEALED_CLASSES);
flag = Flags.SEALED;
break;
}
+ if (isPrimitiveModifier()) {
+ flag = Flags.PRIMITIVE_CLASS;
+ break;
+ }
+ if (isValueModifier()) {
+ flag = Flags.VALUE_CLASS;
+ break;
+ }
+ if (isIdentityModifier()) {
+ flag = Flags.IDENTITY_TYPE;
+ 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.primitive) {
+ if (allowPrimitiveClasses) {
+ return Source.JDK18;
+ }
+ }
+ if (name == names.value) {
+ if (allowValueClasses) {
+ return Source.JDK18;
+ } else if (shouldWarn) {
+ log.warning(pos, Warnings.RestrictedTypeNotAllowedPreview(name, Source.JDK18));
+ }
+ }
+ if (name == names.identity) {
+ if (allowPrimitiveClasses) {
+ return Source.JDK18;
+ } else if (shouldWarn) {
+ log.warning(pos, Warnings.RestrictedTypeNotAllowedPreview(name, Source.JDK18));
+ }
+ }
if (name == names.sealed) {
if (allowSealedTypes) {
return Source.JDK15;
} else if (shouldWarn) {
log.warning(pos, Warnings.RestrictedTypeNotAllowedPreview(name, Source.JDK15));
fields.add(field);
}
for (JCTree def : defs) {
if (def.hasTag(METHODDEF)) {
JCMethodDecl methDef = (JCMethodDecl) def;
! if (methDef.name == names.init && methDef.params.isEmpty() && (methDef.mods.flags & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0) {
ListBuffer<JCVariableDecl> tmpParams = new ListBuffer<>();
for (JCVariableDecl param : headerFields) {
tmpParams.add(F.at(param)
// we will get flags plus annotations from the record component
.VarDef(F.Modifiers(Flags.PARAMETER | Flags.GENERATED_MEMBER | Flags.MANDATED | param.mods.flags & Flags.VARARGS,
fields.add(field);
}
for (JCTree def : defs) {
if (def.hasTag(METHODDEF)) {
JCMethodDecl methDef = (JCMethodDecl) def;
! // TODO - specifically for record.
+ if (names.isInitOrVNew(methDef.name) && methDef.params.isEmpty() && (methDef.mods.flags & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0) {
ListBuffer<JCVariableDecl> tmpParams = new ListBuffer<>();
for (JCVariableDecl param : headerFields) {
tmpParams.add(F.at(param)
// we will get flags plus annotations from the record component
.VarDef(F.Modifiers(Flags.PARAMETER | Flags.GENERATED_MEMBER | Flags.MANDATED | param.mods.flags & Flags.VARARGS,
}
}
return false;
}
+ protected boolean isPrimitiveModifier() {
+ if (token.kind == IDENTIFIER && token.name() == names.primitive) {
+ boolean isPrimitiveModifier = 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:
+ isPrimitiveModifier = true;
+ break;
+ case IDENTIFIER: // primitive record R || primitive primitive || primitive identity || primitive value || new primitive Comparable() {}
+ if (next.name() == names.record || next.name() == names.primitive || next.name() == names.identity
+ || next.name() == names.value || (mode & EXPR) != 0)
+ isPrimitiveModifier = true;
+ break;
+ }
+ if (isPrimitiveModifier) {
+ checkSourceLevel(Feature.PRIMITIVE_CLASSES);
+ return true;
+ }
+ }
+ 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 || value identity || value primitive || new value Comparable() {} ??
+ if (next.name() == names.record || next.name() == names.value || next.name() == names.identity
+ || next.name() == names.primitive || (mode & EXPR) != 0)
+ isValueModifier = true;
+ break;
+ }
+ if (isValueModifier) {
+ checkSourceLevel(Feature.VALUE_CLASSES);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ protected boolean isIdentityModifier() {
+ if (token.kind == IDENTIFIER && token.name() == names.identity) {
+ boolean isIdentityModifier = 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:
+ isIdentityModifier = true;
+ break;
+ case IDENTIFIER: // identity record R || identity primitive || || identity identity || identity value || new identity Comparable() {}
+ if (next.name() == names.record || next.name() == names.primitive || next.name() == names.identity
+ || next.name() == names.value || (mode & EXPR) != 0)
+ isIdentityModifier = true;
+ break;
+ }
+ if (isIdentityModifier) {
+ 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;
default -> false;
};
}
/** MethodDeclaratorRest =
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 ||
+ next.name() == names.value ||
+ next.name() == names.identity;
default -> false;
};
}
/** MethodDeclaratorRest =
try {
this.receiverParam = null;
// Parsing formalParameters sets the receiverParam, if present
List<JCVariableDecl> params = List.nil();
List<JCExpression> thrown = List.nil();
! if (!isRecord || name != names.init || token.kind == LPAREN) {
params = formalParameters();
if (!isVoid) type = bracketsOpt(type);
if (token.kind == THROWS) {
nextToken();
thrown = qualidentList(true);
try {
this.receiverParam = null;
// Parsing formalParameters sets the receiverParam, if present
List<JCVariableDecl> params = List.nil();
List<JCExpression> thrown = List.nil();
! if (!isRecord || !names.isInitOrVNew(name) || token.kind == LPAREN) {
params = formalParameters();
if (!isVoid) type = bracketsOpt(type);
if (token.kind == THROWS) {
nextToken();
thrown = qualidentList(true);
void checkSourceLevel(Feature feature) {
checkSourceLevel(token.pos, feature);
}
protected void checkSourceLevel(int pos, Feature feature) {
! if (preview.isPreview(feature) && !preview.isEnabled()) {
//preview feature without --preview flag, error
log.error(DiagnosticFlag.SOURCE_LEVEL, pos, preview.disabledError(feature));
} else if (!feature.allowedInSource(source)) {
//incompatible source level, error
log.error(DiagnosticFlag.SOURCE_LEVEL, pos, feature.error(source.name));
void checkSourceLevel(Feature feature) {
checkSourceLevel(token.pos, feature);
}
protected void checkSourceLevel(int pos, Feature feature) {
! if (feature == Feature.PRIMITIVE_CLASSES && !allowPrimitiveClasses) {
+ // primitive classes are special
+ log.error(DiagnosticFlag.SOURCE_LEVEL, pos, feature.error(source.name));
+ } else if (preview.isPreview(feature) && !preview.isEnabled()) {
//preview feature without --preview flag, error
log.error(DiagnosticFlag.SOURCE_LEVEL, pos, preview.disabledError(feature));
} else if (!feature.allowedInSource(source)) {
//incompatible source level, error
log.error(DiagnosticFlag.SOURCE_LEVEL, pos, feature.error(source.name));
< prev index next >