/*
 * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package jdk.jshell;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.stream.Stream;

import static java.util.stream.Collectors.toList;
import static jdk.jshell.Util.PREFIX_PATTERN;
import static jdk.jshell.Util.REPL_PACKAGE;
import static jdk.internal.jshell.debug.InternalDebugControl.DBG_DEP;

Maintain relationships between the significant entities: Snippets, internal snippet index, Keys, etc.
Author:Robert Field
/** * Maintain relationships between the significant entities: Snippets, * internal snippet index, Keys, etc. * @author Robert Field */
final class SnippetMaps { private final List<Snippet> keyIndexToSnippet = new ArrayList<>(); private final Set<Snippet> snippets = new LinkedHashSet<>(); private final Map<String, Set<Integer>> dependencies = new HashMap<>(); private final JShell state; SnippetMaps(JShell proc) { this.state = proc; } void installSnippet(Snippet sn) { if (sn != null && snippets.add(sn)) { if (sn.key() != null) { sn.setId((state.idGenerator != null) ? state.idGenerator.apply(sn, sn.key().index()) : "" + sn.key().index()); setSnippet(sn.key().index(), sn); } } } private void setSnippet(int ki, Snippet snip) { while (ki >= keyIndexToSnippet.size()) { keyIndexToSnippet.add(null); } keyIndexToSnippet.set(ki, snip); } Snippet getSnippet(Key key) { return getSnippet(key.index()); } Snippet getSnippet(int ki) { Snippet sn = getSnippetDeadOrAlive(ki); return (sn != null && !sn.status().isActive()) ? null : sn; } Snippet getSnippetDeadOrAlive(int ki) { if (ki >= keyIndexToSnippet.size()) { return null; } return keyIndexToSnippet.get(ki); } List<Snippet> snippetList() { return new ArrayList<>(snippets); } String packageAndImportsExcept(Set<Key> except, Collection<Snippet> plus) { StringBuilder sb = new StringBuilder(); sb.append("package ").append(REPL_PACKAGE).append(";\n"); for (Snippet si : keyIndexToSnippet) { if (si != null && si.status().isDefined() && (except == null || !except.contains(si.key()))) { sb.append(si.importLine(state)); } } if (plus != null) { plus.stream() .forEach(psi -> sb.append(psi.importLine(state))); } return sb.toString(); } List<Snippet> getDependents(Snippet snip) { if (!snip.kind().isPersistent()) { return Collections.emptyList(); } Set<Integer> depset; if (snip.unitName.equals("*")) { // star import depset = new HashSet<>(); for (Set<Integer> as : dependencies.values()) { depset.addAll(as); } } else { depset = dependencies.get(snip.name()); } if (depset == null) { return Collections.emptyList(); } List<Snippet> deps = new ArrayList<>(); for (Integer dss : depset) { Snippet dep = getSnippetDeadOrAlive(dss); if (dep != null) { deps.add(dep); state.debug(DBG_DEP, "Found dependency %s -> %s\n", snip.name(), dep.name()); } } return deps; } void mapDependencies(Snippet snip) { addDependencies(snip.declareReferences(), snip); addDependencies(snip.bodyReferences(), snip); } private void addDependencies(Collection<String> refs, Snippet snip) { if (refs == null) return; for (String ref : refs) { dependencies.computeIfAbsent(ref, k -> new HashSet<>()) .add(snip.key().index()); state.debug(DBG_DEP, "Added dependency %s -> %s\n", ref, snip.name()); } } String fullClassNameAndPackageToClass(String full, String pkg) { Matcher mat = PREFIX_PATTERN.matcher(full); if (mat.lookingAt()) { return full.substring(mat.end()); } state.debug(DBG_DEP, "SM %s %s\n", full, pkg); List<String> klasses = importSnippets() .filter(isi -> !isi.isStar) .map(isi -> isi.fullname) .collect(toList()); for (String k : klasses) { if (k.equals(full)) { return full.substring(full.lastIndexOf(".")+1, full.length()); } } List<String> pkgs = importSnippets() .filter(isi -> isi.isStar) .map(isi -> isi.fullname.substring(0, isi.fullname.lastIndexOf("."))) .collect(toList()); pkgs.add(0, "java.lang"); for (String ipkg : pkgs) { if (!ipkg.isEmpty() && ipkg.equals(pkg)) { return full.substring(pkg.length() + 1); } } return full; }
Compute the set of imports to prepend to a snippet
Returns:a stream of the import needed
/** * Compute the set of imports to prepend to a snippet * @return a stream of the import needed */
private Stream<ImportSnippet> importSnippets() { return state.keyMap.importKeys() .map(key -> (ImportSnippet)getSnippet(key)) .filter(sn -> sn != null && state.status(sn).isDefined()); } }