< prev index next >

src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java

Print this page
*** 35,13 ***
--- 35,15 ---
  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.*;

*** 49,18 ***
--- 51,20 ---
  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;

*** 189,10 ***
--- 193,12 ---
          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")

*** 212,10 ***
--- 218,11 ---
          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 = parser.allowValueClasses;
      }
  
      protected AbstractEndPosTable newEndPosTable(boolean keepEndPositions) {
          return  keepEndPositions
                  ? new SimpleEndPosTable(this)

*** 249,10 ***
--- 256,14 ---
  
      /** 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.

*** 1566,12 ***
                              // 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());
--- 1577,12 ---
                              // 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());

*** 1815,11 ***
       * If we see an identifier followed by a '&lt;' it could be an unbound
       * method reference or a binary expression. To disambiguate, look for a
       * matching '&gt;' 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:
--- 1826,11 ---
       * If we see an identifier followed by a '&lt;' it could be an unbound
       * method reference or a binary expression. To disambiguate, look for a
       * matching '&gt;' 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:

*** 2484,15 ***
      }
  
      /** 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())));
--- 2495,18 ---
      }
  
      /** 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())));

*** 2561,11 ***
          } 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)));
--- 2575,15 ---
          } 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)));

*** 2586,11 ***
          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 )
       */
--- 2604,11 ---
          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 )
       */

*** 2664,18 ***
      /** 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));
      }
  
--- 2682,19 ---
      /** 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));
      }
  

*** 2905,10 ***
--- 2924,15 ---
                      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;

*** 3398,11 ***
          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();
--- 3422,14 ---
          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();

*** 3495,10 ***
--- 3522,15 ---
                  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);

*** 3761,10 ***
--- 3793,17 ---
                  return Source.JDK14;
              } else if (shouldWarn) {
                  log.warning(pos, Warnings.RestrictedTypeNotAllowedPreview(name, Source.JDK14));
              }
          }
+         if (name == names.value) {
+             if (allowValueClasses) {
+                 return Source.JDK22;
+             } else if (shouldWarn) {
+                 log.warning(pos, Warnings.RestrictedTypeNotAllowedPreview(name, Source.JDK22));
+             }
+         }
          if (name == names.sealed) {
              if (allowSealedTypes) {
                  return Source.JDK15;
              } else if (shouldWarn) {
                  log.warning(pos, Warnings.RestrictedTypeNotAllowedPreview(name, Source.JDK15));

*** 4828,10 ***
--- 4867,36 ---
              }
          }
          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);

*** 4855,11 ***
                  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 =
--- 4920,13 ---
                  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 >