langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java
changeset 39370 437ba9bd2582
parent 38908 f0c186d76c8a
child 39807 ba0ff343d241
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java	Fri Jul 01 14:16:28 2016 -0700
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java	Fri Jul 01 14:41:07 2016 -0700
@@ -52,6 +52,7 @@
 import jdk.jshell.Key.ErroneousKey;
 import jdk.jshell.Key.MethodKey;
 import jdk.jshell.Key.TypeDeclKey;
+import jdk.jshell.Snippet.Kind;
 import jdk.jshell.Snippet.SubKind;
 import jdk.jshell.TaskFactory.AnalyzeTask;
 import jdk.jshell.TaskFactory.BaseTask;
@@ -62,6 +63,7 @@
 import jdk.jshell.Snippet.Status;
 import static java.util.stream.Collectors.toList;
 import static java.util.stream.Collectors.toSet;
+import static java.util.Collections.singletonList;
 import static jdk.internal.jshell.debug.InternalDebugControl.DBG_GEN;
 import static jdk.jshell.Util.DOIT_METHOD_NAME;
 import static jdk.jshell.Util.PREFIX_PATTERN;
@@ -89,24 +91,75 @@
         this.state = state;
     }
 
+    /**
+     * Evaluates a snippet of source.
+     *
+     * @param userSource the source of the snippet
+     * @return the list of primary and update events
+     * @throws IllegalStateException
+     */
     List<SnippetEvent> eval(String userSource) throws IllegalStateException {
+        List<SnippetEvent> allEvents = new ArrayList<>();
+        for (Snippet snip : sourceToSnippets(userSource)) {
+            if (snip.kind() == Kind.ERRONEOUS) {
+                state.maps.installSnippet(snip);
+                allEvents.add(new SnippetEvent(
+                        snip, Status.NONEXISTENT, Status.REJECTED,
+                        false, null, null, null));
+            } else {
+                allEvents.addAll(declare(snip, snip.syntheticDiags()));
+            }
+        }
+        return allEvents;
+    }
+
+    /**
+     * Converts the user source of a snippet into a Snippet list -- Snippet will
+     * have wrappers.
+     *
+     * @param userSource the source of the snippet
+     * @return usually a singleton list of Snippet, but may be empty or multiple
+     */
+    List<Snippet> sourceToSnippetsWithWrappers(String userSource) {
+        List<Snippet> snippets = sourceToSnippets(userSource);
+        for (Snippet snip : snippets) {
+            if (snip.outerWrap() == null) {
+                snip.setOuterWrap(
+                        (snip.kind() == Kind.IMPORT)
+                                ? state.outerMap.wrapImport(snip.guts(), snip)
+                                : state.outerMap.wrapInTrialClass(snip.guts())
+                );
+            }
+        }
+        return snippets;
+    }
+
+    /**
+     * Converts the user source of a snippet into a Snippet object (or list of
+     * objects in the case of: int x, y, z;).  Does not install the Snippets
+     * or execute them.
+     *
+     * @param userSource the source of the snippet
+     * @return usually a singleton list of Snippet, but may be empty or multiple
+     */
+    private List<Snippet> sourceToSnippets(String userSource) {
         String compileSource = Util.trimEnd(new MaskCommentsAndModifiers(userSource, false).cleared());
         if (compileSource.length() == 0) {
             return Collections.emptyList();
         }
-        // String folding messes up position information.
         ParseTask pt = state.taskFactory.new ParseTask(compileSource);
+        List<? extends Tree> units = pt.units();
+        if (units.isEmpty()) {
+            return compileFailResult(pt, userSource, Kind.ERRONEOUS);
+        }
+        Tree unitTree = units.get(0);
         if (pt.getDiagnostics().hasOtherThanNotStatementErrors()) {
-            return compileFailResult(pt, userSource);
+            return compileFailResult(pt, userSource, kindOfTree(unitTree));
         }
 
-        List<? extends Tree> units = pt.units();
-        if (units.isEmpty()) {
-            return compileFailResult(pt, userSource);
-        }
-        // Erase illegal modifiers
+        // Erase illegal/ignored modifiers
         compileSource = new MaskCommentsAndModifiers(compileSource, true).cleared();
-        Tree unitTree = units.get(0);
+
         state.debug(DBG_GEN, "Kind: %s -- %s\n", unitTree.getKind(), unitTree);
         switch (unitTree.getKind()) {
             case IMPORT:
@@ -130,7 +183,7 @@
         }
     }
 
-    private List<SnippetEvent> processImport(String userSource, String compileSource) {
+    private List<Snippet> processImport(String userSource, String compileSource) {
         Wrap guts = Wrap.simpleWrap(compileSource);
         Matcher mat = IMPORT_PATTERN.matcher(compileSource);
         String fullname;
@@ -155,7 +208,7 @@
                 : (isStatic ? SINGLE_STATIC_IMPORT_SUBKIND : SINGLE_TYPE_IMPORT_SUBKIND);
         Snippet snip = new ImportSnippet(state.keyMap.keyForImport(keyName, snippetKind),
                 userSource, guts, fullname, name, snippetKind, fullkey, isStatic, isStar);
-        return declare(snip);
+        return singletonList(snip);
     }
 
     private static class EvalPretty extends Pretty {
@@ -187,8 +240,8 @@
         }
     }
 
-    private List<SnippetEvent> processVariables(String userSource, List<? extends Tree> units, String compileSource, ParseTask pt) {
-        List<SnippetEvent> allEvents = new ArrayList<>();
+    private List<Snippet> processVariables(String userSource, List<? extends Tree> units, String compileSource, ParseTask pt) {
+        List<Snippet> snippets = new ArrayList<>();
         TreeDissector dis = TreeDissector.createByFirstClass(pt);
         for (Tree unitTree : units) {
             VariableTree vt = (VariableTree) unitTree;
@@ -224,18 +277,16 @@
             int nameEnd = nameStart + name.length();
             Range rname = new Range(nameStart, nameEnd);
             Wrap guts = Wrap.varWrap(compileSource, rtype, sbBrackets.toString(), rname, rinit);
+            DiagList modDiag = modifierDiagnostics(vt.getModifiers(), dis, true);
             Snippet snip = new VarSnippet(state.keyMap.keyForVariable(name), userSource, guts,
                     name, subkind, typeName,
-                    tds.declareReferences());
-            DiagList modDiag = modifierDiagnostics(vt.getModifiers(), dis, true);
-            List<SnippetEvent> res1 = declare(snip, modDiag);
-            allEvents.addAll(res1);
+                    tds.declareReferences(), modDiag);
+            snippets.add(snip);
         }
-
-        return allEvents;
+        return snippets;
     }
 
-    private List<SnippetEvent> processExpression(String userSource, String compileSource) {
+    private List<Snippet> processExpression(String userSource, String compileSource) {
         String name = null;
         ExpressionInfo ei = typeOfExpression(compileSource);
         ExpressionTree assignVar;
@@ -266,7 +317,7 @@
                 guts = Wrap.tempVarWrap(compileSource, typeName, name);
                 Collection<String> declareReferences = null; //TODO
                 snip = new VarSnippet(state.keyMap.keyForVariable(name), userSource, guts,
-                        name, SubKind.TEMP_VAR_EXPRESSION_SUBKIND, typeName, declareReferences);
+                        name, SubKind.TEMP_VAR_EXPRESSION_SUBKIND, typeName, declareReferences, null);
             } else {
                 guts = Wrap.methodReturnWrap(compileSource);
                 snip = new ExpressionSnippet(state.keyMap.keyForExpression(name, typeName), userSource, guts,
@@ -282,15 +333,15 @@
                     at = trialCompile(guts);
                 }
                 if (at.hasErrors()) {
-                    return compileFailResult(at, userSource);
+                    return compileFailResult(at, userSource, Kind.EXPRESSION);
                 }
             }
             snip = new StatementSnippet(state.keyMap.keyForStatement(), userSource, guts);
         }
-        return declare(snip);
+        return singletonList(snip);
     }
 
-    private List<SnippetEvent> processClass(String userSource, Tree unitTree, String compileSource, SubKind snippetKind, ParseTask pt) {
+    private List<Snippet> processClass(String userSource, Tree unitTree, String compileSource, SubKind snippetKind, ParseTask pt) {
         TreeDependencyScanner tds = new TreeDependencyScanner();
         tds.scan(unitTree);
 
@@ -306,11 +357,11 @@
         Wrap guts = Wrap.classMemberWrap(compileSource);
         Snippet snip = new TypeDeclSnippet(key, userSource, guts,
                 name, snippetKind,
-                corralled, tds.declareReferences(), tds.bodyReferences());
-        return declare(snip, modDiag);
+                corralled, tds.declareReferences(), tds.bodyReferences(), modDiag);
+        return singletonList(snip);
     }
 
-    private List<SnippetEvent> processStatement(String userSource, String compileSource) {
+    private List<Snippet> processStatement(String userSource, String compileSource) {
         Wrap guts = Wrap.methodWrap(compileSource);
         // Check for unreachable by trying
         AnalyzeTask at = trialCompile(guts);
@@ -325,15 +376,15 @@
                         at = trialCompile(guts);
                     }
                     if (at.hasErrors()) {
-                        return compileFailResult(at, userSource);
+                        return compileFailResult(at, userSource, Kind.STATEMENT);
                     }
                 }
             } else {
-                return compileFailResult(at, userSource);
+                return compileFailResult(at, userSource, Kind.STATEMENT);
             }
         }
         Snippet snip = new StatementSnippet(state.keyMap.keyForStatement(), userSource, guts);
-        return declare(snip);
+        return singletonList(snip);
     }
 
     private AnalyzeTask trialCompile(Wrap guts) {
@@ -341,7 +392,7 @@
         return state.taskFactory.new AnalyzeTask(outer);
     }
 
-    private List<SnippetEvent> processMethod(String userSource, Tree unitTree, String compileSource, ParseTask pt) {
+    private List<Snippet> processMethod(String userSource, Tree unitTree, String compileSource, ParseTask pt) {
         TreeDependencyScanner tds = new TreeDependencyScanner();
         tds.scan(unitTree);
         TreeDissector dis = TreeDissector.createByFirstClass(pt);
@@ -360,7 +411,7 @@
         Wrap corralled = new Corraller(key.index(), pt.getContext()).corralMethod(mt);
 
         if (modDiag.hasErrors()) {
-            return compileFailResult(modDiag, userSource);
+            return compileFailResult(modDiag, userSource, Kind.METHOD);
         }
         Wrap guts = Wrap.classMemberWrap(compileSource);
         Range typeRange = dis.treeToRange(returnType);
@@ -368,37 +419,76 @@
 
         Snippet snip = new MethodSnippet(key, userSource, guts,
                 name, signature,
-                corralled, tds.declareReferences(), tds.bodyReferences());
-        return declare(snip, modDiag);
+                corralled, tds.declareReferences(), tds.bodyReferences(), modDiag);
+        return singletonList(snip);
     }
 
-    /**
-     * The snippet has failed, return with the rejected event
-     *
-     * @param xt the task from which to extract the failure diagnostics
-     * @param userSource the incoming bad user source
-     * @return a rejected snippet event
-     */
-    private List<SnippetEvent> compileFailResult(BaseTask xt, String userSource) {
-        return compileFailResult(xt.getDiagnostics(), userSource);
+    private Kind kindOfTree(Tree tree) {
+        switch (tree.getKind()) {
+            case IMPORT:
+                return Kind.IMPORT;
+            case VARIABLE:
+                return Kind.VAR;
+            case EXPRESSION_STATEMENT:
+                return Kind.EXPRESSION;
+            case CLASS:
+            case ENUM:
+            case ANNOTATION_TYPE:
+            case INTERFACE:
+                return Kind.TYPE_DECL;
+            case METHOD:
+                return Kind.METHOD;
+            default:
+                return Kind.STATEMENT;
+        }
     }
 
     /**
-     * The snippet has failed, return with the rejected event
+     * The snippet has failed, return with the rejected snippet
+     *
+     * @param xt the task from which to extract the failure diagnostics
+     * @param userSource the incoming bad user source
+     * @return a rejected snippet
+     */
+    private List<Snippet> compileFailResult(BaseTask xt, String userSource, Kind probableKind) {
+        return compileFailResult(xt.getDiagnostics(), userSource, probableKind);
+    }
+
+    /**
+     * The snippet has failed, return with the rejected snippet
      *
      * @param diags the failure diagnostics
      * @param userSource the incoming bad user source
-     * @return a rejected snippet event
+     * @return a rejected snippet
      */
-    private List<SnippetEvent> compileFailResult(DiagList diags, String userSource) {
+    private List<Snippet> compileFailResult(DiagList diags, String userSource, Kind probableKind) {
         ErroneousKey key = state.keyMap.keyForErroneous();
-        Snippet snip = new ErroneousSnippet(key, userSource, null, SubKind.UNKNOWN_SUBKIND);
+        Snippet snip = new ErroneousSnippet(key, userSource, null,
+                probableKind, SubKind.UNKNOWN_SUBKIND);
         snip.setFailed(diags);
-        state.maps.installSnippet(snip);
-        return Collections.singletonList(new SnippetEvent(
-                snip, Status.NONEXISTENT, Status.REJECTED,
-                false, null, null, null)
-        );
+
+        // Install  wrapper for query by SourceCodeAnalysis.wrapper
+        String compileSource = Util.trimEnd(new MaskCommentsAndModifiers(userSource, true).cleared());
+        OuterWrap outer;
+        switch (probableKind) {
+            case IMPORT:
+                outer = state.outerMap.wrapImport(Wrap.simpleWrap(compileSource), snip);
+                break;
+            case EXPRESSION:
+                outer = state.outerMap.wrapInTrialClass(Wrap.methodReturnWrap(compileSource));
+                break;
+            case VAR:
+            case TYPE_DECL:
+            case METHOD:
+                outer = state.outerMap.wrapInTrialClass(Wrap.classMemberWrap(compileSource));
+                break;
+            default:
+                outer = state.outerMap.wrapInTrialClass(Wrap.methodWrap(compileSource));
+                break;
+        }
+        snip.setOuterWrap(outer);
+
+        return singletonList(snip);
     }
 
     private ExpressionInfo typeOfExpression(String expression) {
@@ -430,10 +520,6 @@
         return events(c, outs, null, null);
     }
 
-    private List<SnippetEvent> declare(Snippet si) {
-        return declare(si, new DiagList());
-    }
-
     private List<SnippetEvent> declare(Snippet si, DiagList generatedDiagnostics) {
         Unit c = new Unit(state, si, null, generatedDiagnostics);
         Set<Unit> ins = new LinkedHashSet<>();