src/jdk.jshell/share/classes/jdk/jshell/SnippetMaps.java
changeset 47216 71c04702a3d5
parent 38908 f0c186d76c8a
equal deleted inserted replaced
47215:4ebc2e2fb97c 47216:71c04702a3d5
       
     1 /*
       
     2  * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 package jdk.jshell;
       
    27 
       
    28 import java.util.ArrayList;
       
    29 import java.util.Collection;
       
    30 import java.util.Collections;
       
    31 import java.util.HashMap;
       
    32 import java.util.HashSet;
       
    33 import java.util.LinkedHashSet;
       
    34 import java.util.List;
       
    35 import java.util.Map;
       
    36 import java.util.Set;
       
    37 import java.util.regex.Matcher;
       
    38 import java.util.stream.Stream;
       
    39 
       
    40 import static java.util.stream.Collectors.toList;
       
    41 import static jdk.jshell.Util.PREFIX_PATTERN;
       
    42 import static jdk.jshell.Util.REPL_PACKAGE;
       
    43 import static jdk.internal.jshell.debug.InternalDebugControl.DBG_DEP;
       
    44 
       
    45 /**
       
    46  * Maintain relationships between the significant entities: Snippets,
       
    47  * internal snippet index, Keys, etc.
       
    48  * @author Robert Field
       
    49  */
       
    50 final class SnippetMaps {
       
    51 
       
    52     private final List<Snippet> keyIndexToSnippet = new ArrayList<>();
       
    53     private final Set<Snippet> snippets = new LinkedHashSet<>();
       
    54     private final Map<String, Set<Integer>> dependencies = new HashMap<>();
       
    55     private final JShell state;
       
    56 
       
    57     SnippetMaps(JShell proc) {
       
    58         this.state = proc;
       
    59     }
       
    60 
       
    61     void installSnippet(Snippet sn) {
       
    62         if (sn != null && snippets.add(sn)) {
       
    63             if (sn.key() != null) {
       
    64                 sn.setId((state.idGenerator != null)
       
    65                         ? state.idGenerator.apply(sn, sn.key().index())
       
    66                         : "" + sn.key().index());
       
    67                 setSnippet(sn.key().index(), sn);
       
    68             }
       
    69         }
       
    70     }
       
    71 
       
    72     private void setSnippet(int ki, Snippet snip) {
       
    73         while (ki >= keyIndexToSnippet.size()) {
       
    74             keyIndexToSnippet.add(null);
       
    75         }
       
    76         keyIndexToSnippet.set(ki, snip);
       
    77     }
       
    78 
       
    79     Snippet getSnippet(Key key) {
       
    80         return getSnippet(key.index());
       
    81     }
       
    82 
       
    83     Snippet getSnippet(int ki) {
       
    84         Snippet sn = getSnippetDeadOrAlive(ki);
       
    85         return (sn != null && !sn.status().isActive())
       
    86                 ? null
       
    87                 : sn;
       
    88     }
       
    89 
       
    90     Snippet getSnippetDeadOrAlive(int ki) {
       
    91         if (ki >= keyIndexToSnippet.size()) {
       
    92             return null;
       
    93         }
       
    94         return keyIndexToSnippet.get(ki);
       
    95     }
       
    96 
       
    97     List<Snippet> snippetList() {
       
    98         return new ArrayList<>(snippets);
       
    99     }
       
   100 
       
   101     String packageAndImportsExcept(Set<Key> except, Collection<Snippet> plus) {
       
   102         StringBuilder sb = new StringBuilder();
       
   103         sb.append("package ").append(REPL_PACKAGE).append(";\n");
       
   104         for (Snippet si : keyIndexToSnippet) {
       
   105             if (si != null && si.status().isDefined() && (except == null || !except.contains(si.key()))) {
       
   106                 sb.append(si.importLine(state));
       
   107             }
       
   108         }
       
   109         if (plus != null) {
       
   110             plus.stream()
       
   111                     .forEach(psi -> sb.append(psi.importLine(state)));
       
   112         }
       
   113         return sb.toString();
       
   114     }
       
   115 
       
   116     List<Snippet> getDependents(Snippet snip) {
       
   117         if (!snip.kind().isPersistent()) {
       
   118             return Collections.emptyList();
       
   119         }
       
   120         Set<Integer> depset;
       
   121         if (snip.unitName.equals("*")) {
       
   122             // star import
       
   123             depset = new HashSet<>();
       
   124             for (Set<Integer> as : dependencies.values()) {
       
   125                 depset.addAll(as);
       
   126             }
       
   127         } else {
       
   128             depset = dependencies.get(snip.name());
       
   129         }
       
   130         if (depset == null) {
       
   131             return Collections.emptyList();
       
   132         }
       
   133         List<Snippet> deps = new ArrayList<>();
       
   134         for (Integer dss : depset) {
       
   135             Snippet dep = getSnippetDeadOrAlive(dss);
       
   136             if (dep != null) {
       
   137                 deps.add(dep);
       
   138                 state.debug(DBG_DEP, "Found dependency %s -> %s\n", snip.name(), dep.name());
       
   139             }
       
   140         }
       
   141         return deps;
       
   142     }
       
   143 
       
   144     void mapDependencies(Snippet snip) {
       
   145         addDependencies(snip.declareReferences(), snip);
       
   146         addDependencies(snip.bodyReferences(),    snip);
       
   147     }
       
   148 
       
   149     private void addDependencies(Collection<String> refs, Snippet snip) {
       
   150         if (refs == null) return;
       
   151         for (String ref : refs) {
       
   152             dependencies.computeIfAbsent(ref, k -> new HashSet<>())
       
   153                         .add(snip.key().index());
       
   154             state.debug(DBG_DEP, "Added dependency %s -> %s\n", ref, snip.name());
       
   155         }
       
   156     }
       
   157 
       
   158     String fullClassNameAndPackageToClass(String full, String pkg) {
       
   159         Matcher mat = PREFIX_PATTERN.matcher(full);
       
   160         if (mat.lookingAt()) {
       
   161             return full.substring(mat.end());
       
   162         }
       
   163         state.debug(DBG_DEP, "SM %s %s\n", full, pkg);
       
   164         List<String> klasses = importSnippets()
       
   165                                .filter(isi -> !isi.isStar)
       
   166                                .map(isi -> isi.fullname)
       
   167                                .collect(toList());
       
   168         for (String k : klasses) {
       
   169             if (k.equals(full)) {
       
   170                 return full.substring(full.lastIndexOf(".")+1, full.length());
       
   171             }
       
   172         }
       
   173         List<String> pkgs = importSnippets()
       
   174                                .filter(isi -> isi.isStar)
       
   175                                .map(isi -> isi.fullname.substring(0, isi.fullname.lastIndexOf(".")))
       
   176                                .collect(toList());
       
   177         pkgs.add(0, "java.lang");
       
   178         for (String ipkg : pkgs) {
       
   179             if (!ipkg.isEmpty() && ipkg.equals(pkg)) {
       
   180                 return full.substring(pkg.length() + 1);
       
   181             }
       
   182         }
       
   183         return full;
       
   184     }
       
   185 
       
   186     /**
       
   187      * Compute the set of imports to prepend to a snippet
       
   188      * @return a stream of the import needed
       
   189      */
       
   190     private Stream<ImportSnippet> importSnippets() {
       
   191         return state.keyMap.importKeys()
       
   192                 .map(key -> (ImportSnippet)getSnippet(key))
       
   193                 .filter(sn -> sn != null && state.status(sn).isDefined());
       
   194     }
       
   195 }