< prev index next >

src/jdk.jshell/share/classes/jdk/jshell/CompletenessAnalyzer.java

Print this page

        

@@ -50,18 +50,21 @@
 import jdk.jshell.TaskFactory.Worker;
 import java.util.List;
 import java.util.function.Function;
 import java.util.function.Supplier;
 
+import com.sun.tools.javac.util.Names;
+
 /**
  * Low level scanner to determine completeness of input.
  * @author Robert Field
  */
 class CompletenessAnalyzer {
 
     private final ScannerFactory scannerFactory;
     private final JShell proc;
+    private final Names names;
 
     private static Completeness error() {
         return Completeness.UNKNOWN;  // For breakpointing
     }
 

@@ -79,17 +82,19 @@
         this.proc = proc;
         Context context = new Context();
         Log log = CaLog.createLog(context);
         context.put(Log.class, log);
         context.put(Source.class, Source.JDK9);
+        names = Names.instance(context);
         scannerFactory = ScannerFactory.instance(context);
     }
 
     CaInfo scan(String s) {
         try {
             Parser parser = new Parser(
                     () -> new Matched(scannerFactory.newScanner(s, false)),
+                    names,
                     worker -> proc.taskFactory.parse(s, worker));
             Completeness stat = parser.parseUnit();
             int endPos = stat == Completeness.UNKNOWN
                     ? s.length()
                     : parser.endPos();

@@ -159,10 +164,11 @@
     private static final int XANY1         = XEXPR1o | XDECL1o | XSTMT1o;  // Mask: first in statement, declaration, or expression
     private static final int XTERM         = 0b100000000;               // Can terminate (last before EOF)
     private static final int XSTART        = 0b1000000000;              // Boundary, must be XTERM before
     private static final int XERRO         = 0b10000000000;             // Is an error
     private static final int XBRACESNEEDED = 0b100000000000;            // Expect {ANY} LBRACE
+    private static final int XMODIFIER     = 0b1000000000000;           // Modifier
 
     /**
      * An extension of the compiler's TokenKind which adds our combined/processed
      * kinds. Also associates each TK with a union of acceptable kinds of code
      * position it can occupy.  For example: IDENTIFER is XEXPR1|XDECL1|XTERM,

@@ -184,10 +190,13 @@
         EOF(TokenKind.EOF, 0),  //
         ERROR(TokenKind.ERROR, XERRO),  //
         IDENTIFIER(TokenKind.IDENTIFIER, XEXPR1|XDECL1|XTERM),  //
         UNDERSCORE(TokenKind.UNDERSCORE, XERRO),  //  _
         CLASS(TokenKind.CLASS, XEXPR|XDECL1|XBRACESNEEDED),  //  class decl (MAPPED: DOTCLASS)
+        RECORD(TokenKind.RECORD, XEXPR|XDECL1),  //  record decl (MAPPED: DOTCLASS)
+        SEALED(TokenKind.SEALED, XEXPR|XDECL1),  //  sealed class decl (MAPPED: DOTCLASS)
+        PERMITS(TokenKind.PERMITS, XEXPR|XDECL),  // permits classlist
         MONKEYS_AT(TokenKind.MONKEYS_AT, XEXPR|XDECL1),  //  @
         IMPORT(TokenKind.IMPORT, XDECL1|XSTART),  //  import -- consider declaration
         SEMI(TokenKind.SEMI, XSTMT1|XTERM|XSTART),  //  ;
 
         // Shouldn't see -- error

@@ -210,22 +219,23 @@
         FLOAT(TokenKind.FLOAT, XEXPR1|XDECL1),  //  float
         INT(TokenKind.INT, XEXPR1|XDECL1),  //  int
         LONG(TokenKind.LONG, XEXPR1|XDECL1),  //  long
         SHORT(TokenKind.SHORT, XEXPR1|XDECL1),  //  short
         VOID(TokenKind.VOID, XEXPR1|XDECL1),  //  void
+        VAR(TokenKind.VAR, XEXPR1|XDECL1|XTERM),  //  var
 
         // Modifiers keywords
-        ABSTRACT(TokenKind.ABSTRACT, XDECL1),  //  abstract
-        FINAL(TokenKind.FINAL, XDECL1),  //  final
-        NATIVE(TokenKind.NATIVE, XDECL1),  //  native
-        STATIC(TokenKind.STATIC, XDECL1),  //  static
-        STRICTFP(TokenKind.STRICTFP, XDECL1),  //  strictfp
-        PRIVATE(TokenKind.PRIVATE, XDECL1),  //  private
-        PROTECTED(TokenKind.PROTECTED, XDECL1),  //  protected
-        PUBLIC(TokenKind.PUBLIC, XDECL1),  //  public
-        TRANSIENT(TokenKind.TRANSIENT, XDECL1),  //  transient
-        VOLATILE(TokenKind.VOLATILE, XDECL1),  //  volatile
+        ABSTRACT(TokenKind.ABSTRACT, XDECL1 | XMODIFIER),  //  abstract
+        FINAL(TokenKind.FINAL, XDECL1 | XMODIFIER),  //  final
+        NATIVE(TokenKind.NATIVE, XDECL1 | XMODIFIER),  //  native
+        STATIC(TokenKind.STATIC, XDECL1 | XMODIFIER),  //  static
+        STRICTFP(TokenKind.STRICTFP, XDECL1 | XMODIFIER),  //  strictfp
+        PRIVATE(TokenKind.PRIVATE, XDECL1 | XMODIFIER),  //  private
+        PROTECTED(TokenKind.PROTECTED, XDECL1 | XMODIFIER),  //  protected
+        PUBLIC(TokenKind.PUBLIC, XDECL1 | XMODIFIER),  //  public
+        TRANSIENT(TokenKind.TRANSIENT, XDECL1 | XMODIFIER),  //  transient
+        VOLATILE(TokenKind.VOLATILE, XDECL1 | XMODIFIER),  //  volatile
 
         // Declarations and type parameters (thus expressions)
         EXTENDS(TokenKind.EXTENDS, XEXPR|XDECL),  //  extends
         COMMA(TokenKind.COMMA, XEXPR|XDECL),  //  ,
         AMP(TokenKind.AMP, XEXPR|XDECL, true),  //  &

@@ -384,10 +394,14 @@
 
         boolean isBracesNeeded() {
             return (belongs & XBRACESNEEDED) != 0;
         }
 
+        boolean isModifier() {
+            return (belongs & XMODIFIER) != 0;
+        }
+
         /**
          * After construction, check that all compiler TokenKind values have
          * corresponding TK values.
          */
         static {

@@ -418,27 +432,32 @@
         public final int endPos;
 
         /** The error message **/
         public final String message;
 
+        public final Token tok;
+
         private CT(TK tk, Token tok, String msg) {
             this.kind = tk;
             this.endPos = tok.endPos;
             this.message = msg;
+            this.tok = tok;
             //throw new InternalError(msg); /* for debugging */
         }
 
         private CT(TK tk, Token tok) {
             this.kind = tk;
             this.endPos = tok.endPos;
             this.message = null;
+            this.tok = tok;
         }
 
         private CT(TK tk, int endPos) {
             this.kind = tk;
             this.endPos = endPos;
             this.message = null;
+            this.tok = null;
         }
     }
 
     /**
      * Look for matching tokens (like parens) and other special cases, like "new"

@@ -563,15 +582,18 @@
         private final Supplier<Matched> matchedFactory;
         private final Function<Worker<ParseTask, Completeness>, Completeness> parseFactory;
         private Matched in;
         private CT token;
         private Completeness checkResult;
+        private final Names names;
 
         Parser(Supplier<Matched> matchedFactory,
+               Names names,
                Function<Worker<ParseTask, Completeness>, Completeness> parseFactory) {
             this.matchedFactory = matchedFactory;
             this.parseFactory = parseFactory;
+            this.names = names;
             resetInput();
         }
 
         final void resetInput() {
             this.in = matchedFactory.get();

@@ -650,13 +672,17 @@
             }
         }
 
         public Completeness parseDeclaration() {
             boolean isImport = token.kind == IMPORT;
+            boolean isDatum = false;
+            boolean afterModifiers = false;
             boolean isBracesNeeded = false;
             while (token.kind.isDeclaration()) {
                 isBracesNeeded |= token.kind.isBracesNeeded();
+                isDatum |= !afterModifiers && token.kind == TK.IDENTIFIER && token.tok.name() == names.record;
+                afterModifiers |= !token.kind.isModifier();
                 nextToken();
             }
             switch (token.kind) {
                 case EQ:
                     nextToken();

@@ -671,16 +697,23 @@
                 case EOF:
                     switch (in.prevCT.kind) {
                         case BRACES:
                         case SEMI:
                             return Completeness.COMPLETE;
+                        case VAR:
                         case IDENTIFIER:
                             return isBracesNeeded
                                     ? Completeness.DEFINITELY_INCOMPLETE
                                     : Completeness.COMPLETE_WITH_SEMI;
                         case BRACKETS:
                             return Completeness.COMPLETE_WITH_SEMI;
+                        case PARENS:
+                            if (isDatum) {
+                                return Completeness.COMPLETE_WITH_SEMI;
+                            } else {
+                                return Completeness.DEFINITELY_INCOMPLETE;
+                            }
                         case DOTSTAR:
                             if (isImport) {
                                 return Completeness.COMPLETE_WITH_SEMI;
                             } else {
                                 return Completeness.UNKNOWN;
< prev index next >