< 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 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.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
//is a generic type i.e. A<S>::m
int pos1 = token.pos;
accept(LT);
ListBuffer<JCExpression> args = new ListBuffer<>();
args.append(typeArgument());
// 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
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() {
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:
* 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 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:
}
/** 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())));
} 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)));
} else if (token.kind == LPAREN) {
// 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));
}
/** 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));
}
return toP(F.at(newpos).NewClass(encl, typeArgs, t, args, body));
}
nextToken();
return List.of(classOrRecordOrInterfaceOrEnumDeclaration(modifiersOpt(), token.docComment()));
}
}
}
+ if ((isValueModifier()) && allowValueClasses) {
+ checkSourceLevel(Feature.VALUE_CLASSES);
+ dc = token.docComment();
+ return List.of(classOrRecordOrInterfaceOrEnumDeclaration(modifiersOpt(), dc));
+ }
if (isRecordStart() && allowRecords) {
dc = token.docComment();
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 (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;
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 ||
+ allowValueClasses && next.name() == names.value;
default -> false;
};
}
/** MethodDeclaratorRest =
< prev index next >