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

Print this page




  44 import com.sun.source.tree.VariableTree;
  45 import com.sun.tools.javac.tree.JCTree;
  46 import com.sun.tools.javac.tree.Pretty;
  47 import java.io.IOException;
  48 import java.io.StringWriter;
  49 import java.io.Writer;
  50 import java.util.LinkedHashSet;
  51 import java.util.Set;
  52 import jdk.jshell.Key.ErroneousKey;
  53 import jdk.jshell.Key.MethodKey;
  54 import jdk.jshell.Key.TypeDeclKey;
  55 import jdk.jshell.Snippet.Kind;
  56 import jdk.jshell.Snippet.SubKind;
  57 import jdk.jshell.TaskFactory.AnalyzeTask;
  58 import jdk.jshell.TaskFactory.BaseTask;
  59 import jdk.jshell.TaskFactory.CompileTask;
  60 import jdk.jshell.TaskFactory.ParseTask;
  61 import jdk.jshell.TreeDissector.ExpressionInfo;
  62 import jdk.jshell.Wrap.Range;
  63 import jdk.jshell.Snippet.Status;







  64 import static java.util.stream.Collectors.toList;
  65 import static java.util.stream.Collectors.toSet;
  66 import static java.util.Collections.singletonList;
  67 import static jdk.internal.jshell.debug.InternalDebugControl.DBG_GEN;
  68 import static jdk.jshell.Util.DOIT_METHOD_NAME;
  69 import static jdk.jshell.Util.PREFIX_PATTERN;
  70 import static jdk.jshell.Util.expunge;
  71 import static jdk.jshell.Snippet.SubKind.SINGLE_TYPE_IMPORT_SUBKIND;
  72 import static jdk.jshell.Snippet.SubKind.SINGLE_STATIC_IMPORT_SUBKIND;
  73 import static jdk.jshell.Snippet.SubKind.TYPE_IMPORT_ON_DEMAND_SUBKIND;
  74 import static jdk.jshell.Snippet.SubKind.STATIC_IMPORT_ON_DEMAND_SUBKIND;
  75 
  76 /**
  77  * The Evaluation Engine. Source internal analysis, wrapping control,
  78  * compilation, declaration. redefinition, replacement, and execution.
  79  *
  80  * @author Robert Field
  81  */
  82 class Eval {
  83 


 528 
 529         if (!si.status().isDefined()
 530                 && si.diagnostics().isEmpty()
 531                 && si.unresolved().isEmpty()) {
 532             // did not succeed, but no record of it, extract from others
 533             si.setDiagnostics(outs.stream()
 534                     .flatMap(u -> u.snippet().diagnostics().stream())
 535                     .collect(Collectors.toCollection(DiagList::new)));
 536         }
 537 
 538         // If appropriate, execute the snippet
 539         String value = null;
 540         JShellException exception = null;
 541         if (si.status().isDefined()) {
 542             if (si.isExecutable()) {
 543                 try {
 544                 value = state.executionControl().invoke(si.classFullName(), DOIT_METHOD_NAME);
 545                     value = si.subKind().hasValue()
 546                             ? expunge(value)
 547                             : "";
 548                 } catch (EvalException ex) {



 549                     exception = translateExecutionException(ex);
 550                 } catch (JShellException ex) {
 551                     // UnresolvedReferenceException
 552                     exception = ex;



 553                 }
 554             } else if (si.subKind() == SubKind.VAR_DECLARATION_SUBKIND) {
 555                 switch (((VarSnippet) si).typeName()) {
 556                     case "byte":
 557                     case "short":
 558                     case "int":
 559                     case "long":
 560                         value = "0";
 561                         break;
 562                     case "float":
 563                     case "double":
 564                         value = "0.0";
 565                         break;
 566                     case "boolean":
 567                         value = "false";
 568                         break;
 569                     case "char":
 570                         value = "''";
 571                         break;
 572                     default:


 683             }
 684 
 685             // add any new dependencies to the working set
 686             List<Unit> newDependencies = ins.stream()
 687                     .flatMap(u -> u.effectedDependents())
 688                     .collect(toList());
 689             state.debug(DBG_GEN, "compileAndLoad %s -- deps: %s  success: %s\n",
 690                     ins, newDependencies, success);
 691             if (!ins.addAll(newDependencies) && success) {
 692                 // all classes that could not be directly loaded (because they
 693                 // are new) have been redefined, and no new dependnencies were
 694                 // identified
 695                 ins.stream().forEach(u -> u.finish());
 696                 return ins;
 697             }
 698         }
 699     }
 700 
 701     /**
 702      * If there are classes to load, loads by calling the execution engine.
 703      * @param classnames names of the classes to load.
 704      */
 705     private void load(Collection<String> classnames) {
 706         if (!classnames.isEmpty()) {
 707             state.executionControl().load(classnames);








 708         }
 709     }
 710 
 711     private EvalException translateExecutionException(EvalException ex) {
 712         StackTraceElement[] raw = ex.getStackTrace();
 713         int last = raw.length;
 714         do {
 715             if (last == 0) {
 716                 last = raw.length - 1;
 717                 break;
 718             }
 719         } while (!isWrap(raw[--last]));
 720         StackTraceElement[] elems = new StackTraceElement[last + 1];
 721         for (int i = 0; i <= last; ++i) {
 722             StackTraceElement r = raw[i];
 723             OuterSnippetsClassWrap outer = state.outerMap.getOuter(r.getClassName());
 724             if (outer != null) {
 725                 String klass = expunge(r.getClassName());
 726                 String method = r.getMethodName().equals(DOIT_METHOD_NAME) ? "" : r.getMethodName();
 727                 int wln = r.getLineNumber() - 1;
 728                 int line = outer.wrapLineToSnippetLine(wln) + 1;
 729                 Snippet sn = outer.wrapLineToSnippet(wln);
 730                 String file = "#" + sn.id();
 731                 elems[i] = new StackTraceElement(klass, method, file, line);
 732             } else if (r.getFileName().equals("<none>")) {
 733                 elems[i] = new StackTraceElement(r.getClassName(), r.getMethodName(), null, r.getLineNumber());
 734             } else {
 735                 elems[i] = r;
 736             }
 737         }
 738         String msg = ex.getMessage();
 739         if (msg.equals("<none>")) {
 740             msg = null;
 741         }
 742         return new EvalException(msg, ex.getExceptionClassName(), elems);
 743     }
 744 
 745     private boolean isWrap(StackTraceElement ste) {
 746         return PREFIX_PATTERN.matcher(ste.getClassName()).find();
 747     }
 748 
 749     private DiagList modifierDiagnostics(ModifiersTree modtree,
 750             final TreeDissector dis, boolean isAbstractProhibited) {
 751 
 752         class ModifierDiagnostic extends Diag {
 753 
 754             final boolean fatal;
 755             final String message;
 756 
 757             ModifierDiagnostic(List<Modifier> list, boolean fatal) {
 758                 this.fatal = fatal;
 759                 StringBuilder sb = new StringBuilder();
 760                 for (Modifier mod : list) {
 761                     sb.append("'");
 762                     sb.append(mod.toString());




  44 import com.sun.source.tree.VariableTree;
  45 import com.sun.tools.javac.tree.JCTree;
  46 import com.sun.tools.javac.tree.Pretty;
  47 import java.io.IOException;
  48 import java.io.StringWriter;
  49 import java.io.Writer;
  50 import java.util.LinkedHashSet;
  51 import java.util.Set;
  52 import jdk.jshell.Key.ErroneousKey;
  53 import jdk.jshell.Key.MethodKey;
  54 import jdk.jshell.Key.TypeDeclKey;
  55 import jdk.jshell.Snippet.Kind;
  56 import jdk.jshell.Snippet.SubKind;
  57 import jdk.jshell.TaskFactory.AnalyzeTask;
  58 import jdk.jshell.TaskFactory.BaseTask;
  59 import jdk.jshell.TaskFactory.CompileTask;
  60 import jdk.jshell.TaskFactory.ParseTask;
  61 import jdk.jshell.TreeDissector.ExpressionInfo;
  62 import jdk.jshell.Wrap.Range;
  63 import jdk.jshell.Snippet.Status;
  64 import jdk.jshell.spi.ExecutionControl.ClassBytecodes;
  65 import jdk.jshell.spi.ExecutionControl.ClassInstallException;
  66 import jdk.jshell.spi.ExecutionControl.EngineTerminationException;
  67 import jdk.jshell.spi.ExecutionControl.InternalException;
  68 import jdk.jshell.spi.ExecutionControl.ResolutionException;
  69 import jdk.jshell.spi.ExecutionControl.RunException;
  70 import jdk.jshell.spi.ExecutionControl.UserException;
  71 import static java.util.stream.Collectors.toList;
  72 import static java.util.stream.Collectors.toSet;
  73 import static java.util.Collections.singletonList;
  74 import static jdk.internal.jshell.debug.InternalDebugControl.DBG_GEN;
  75 import static jdk.jshell.Util.DOIT_METHOD_NAME;
  76 import static jdk.jshell.Util.PREFIX_PATTERN;
  77 import static jdk.jshell.Util.expunge;
  78 import static jdk.jshell.Snippet.SubKind.SINGLE_TYPE_IMPORT_SUBKIND;
  79 import static jdk.jshell.Snippet.SubKind.SINGLE_STATIC_IMPORT_SUBKIND;
  80 import static jdk.jshell.Snippet.SubKind.TYPE_IMPORT_ON_DEMAND_SUBKIND;
  81 import static jdk.jshell.Snippet.SubKind.STATIC_IMPORT_ON_DEMAND_SUBKIND;
  82 
  83 /**
  84  * The Evaluation Engine. Source internal analysis, wrapping control,
  85  * compilation, declaration. redefinition, replacement, and execution.
  86  *
  87  * @author Robert Field
  88  */
  89 class Eval {
  90 


 535 
 536         if (!si.status().isDefined()
 537                 && si.diagnostics().isEmpty()
 538                 && si.unresolved().isEmpty()) {
 539             // did not succeed, but no record of it, extract from others
 540             si.setDiagnostics(outs.stream()
 541                     .flatMap(u -> u.snippet().diagnostics().stream())
 542                     .collect(Collectors.toCollection(DiagList::new)));
 543         }
 544 
 545         // If appropriate, execute the snippet
 546         String value = null;
 547         JShellException exception = null;
 548         if (si.status().isDefined()) {
 549             if (si.isExecutable()) {
 550                 try {
 551                     value = state.executionControl().invoke(si.classFullName(), DOIT_METHOD_NAME);
 552                     value = si.subKind().hasValue()
 553                             ? expunge(value)
 554                             : "";
 555                 } catch (ResolutionException ex) {
 556                     DeclarationSnippet sn = (DeclarationSnippet) state.maps.getSnippetDeadOrAlive(ex.id());
 557                     exception = new UnresolvedReferenceException(sn, ex.getStackTrace());
 558                 } catch (UserException ex) {
 559                     exception = translateExecutionException(ex);
 560                 } catch (RunException ex) {
 561                     // StopException - no-op
 562                 } catch (InternalException ex) {
 563                     state.debug(ex, "invoke");
 564                 } catch (EngineTerminationException ex) {
 565                     state.closeDown();
 566                 }
 567             } else if (si.subKind() == SubKind.VAR_DECLARATION_SUBKIND) {
 568                 switch (((VarSnippet) si).typeName()) {
 569                     case "byte":
 570                     case "short":
 571                     case "int":
 572                     case "long":
 573                         value = "0";
 574                         break;
 575                     case "float":
 576                     case "double":
 577                         value = "0.0";
 578                         break;
 579                     case "boolean":
 580                         value = "false";
 581                         break;
 582                     case "char":
 583                         value = "''";
 584                         break;
 585                     default:


 696             }
 697 
 698             // add any new dependencies to the working set
 699             List<Unit> newDependencies = ins.stream()
 700                     .flatMap(u -> u.effectedDependents())
 701                     .collect(toList());
 702             state.debug(DBG_GEN, "compileAndLoad %s -- deps: %s  success: %s\n",
 703                     ins, newDependencies, success);
 704             if (!ins.addAll(newDependencies) && success) {
 705                 // all classes that could not be directly loaded (because they
 706                 // are new) have been redefined, and no new dependnencies were
 707                 // identified
 708                 ins.stream().forEach(u -> u.finish());
 709                 return ins;
 710             }
 711         }
 712     }
 713 
 714     /**
 715      * If there are classes to load, loads by calling the execution engine.
 716      * @param classbytecoes names of the classes to load.
 717      */
 718     private void load(Collection<ClassBytecodes> classbytecoes) {
 719         if (!classbytecoes.isEmpty()) {
 720             ClassBytecodes[] cbcs = classbytecoes.toArray(new ClassBytecodes[classbytecoes.size()]);
 721             try {
 722                 state.executionControl().load(cbcs);
 723                 state.classTracker.markLoaded(cbcs);
 724             } catch (ClassInstallException ex) {
 725                 state.classTracker.markLoaded(cbcs, ex.installed());
 726             } catch (EngineTerminationException ex) {
 727                 state.closeDown();
 728             }
 729         }
 730     }
 731 
 732     private EvalException translateExecutionException(UserException ex) {
 733         StackTraceElement[] raw = ex.getStackTrace();
 734         int last = raw.length;
 735         do {
 736             if (last == 0) {
 737                 last = raw.length - 1;
 738                 break;
 739             }
 740         } while (!isWrap(raw[--last]));
 741         StackTraceElement[] elems = new StackTraceElement[last + 1];
 742         for (int i = 0; i <= last; ++i) {
 743             StackTraceElement r = raw[i];
 744             OuterSnippetsClassWrap outer = state.outerMap.getOuter(r.getClassName());
 745             if (outer != null) {
 746                 String klass = expunge(r.getClassName());
 747                 String method = r.getMethodName().equals(DOIT_METHOD_NAME) ? "" : r.getMethodName();
 748                 int wln = r.getLineNumber() - 1;
 749                 int line = outer.wrapLineToSnippetLine(wln) + 1;
 750                 Snippet sn = outer.wrapLineToSnippet(wln);
 751                 String file = "#" + sn.id();
 752                 elems[i] = new StackTraceElement(klass, method, file, line);
 753             } else if (r.getFileName().equals("<none>")) {
 754                 elems[i] = new StackTraceElement(r.getClassName(), r.getMethodName(), null, r.getLineNumber());
 755             } else {
 756                 elems[i] = r;
 757             }
 758         }
 759         String msg = ex.getMessage();
 760         if (msg.equals("<none>")) {
 761             msg = null;
 762         }
 763         return new EvalException(msg, ex.causeExceptionClass(), elems);
 764     }
 765 
 766     private boolean isWrap(StackTraceElement ste) {
 767         return PREFIX_PATTERN.matcher(ste.getClassName()).find();
 768     }
 769 
 770     private DiagList modifierDiagnostics(ModifiersTree modtree,
 771             final TreeDissector dis, boolean isAbstractProhibited) {
 772 
 773         class ModifierDiagnostic extends Diag {
 774 
 775             final boolean fatal;
 776             final String message;
 777 
 778             ModifierDiagnostic(List<Modifier> list, boolean fatal) {
 779                 this.fatal = fatal;
 780                 StringBuilder sb = new StringBuilder();
 781                 for (Modifier mod : list) {
 782                     sb.append("'");
 783                     sb.append(mod.toString());