diff -r 1c96344ecd49 -r 65ec6de1d6b4 langtools/src/jdk.jshell/share/classes/jdk/jshell/Wrap.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Wrap.java Mon Oct 19 19:15:16 2015 +0200 @@ -0,0 +1,458 @@ +/* + * 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.List; +import static jdk.internal.jshell.remote.RemoteCodes.DOIT_METHOD_NAME; + +/** + * Wrapping of source into Java methods, fields, etc. All but outer layer + * wrapping with imports and class. + * + * @author Robert Field + */ +abstract class Wrap implements GeneralWrap { + + private static Wrap methodWrap(String prefix, String source, String suffix) { + Wrap wunit = new NoWrap(source); + return new DoitMethodWrap(new CompoundWrap(prefix, wunit, suffix)); + } + + public static Wrap methodWrap(String source) { + return methodWrap("", source, semi(source) + " return null;\n"); + } + + public static Wrap methodReturnWrap(String source) { + return methodWrap("return ", source, semi(source)); + } + + public static Wrap methodUnreachableSemiWrap(String source) { + return methodWrap("", source, semi(source)); + } + + public static Wrap methodUnreachableWrap(String source) { + return methodWrap("", source, ""); + } + + public static Wrap corralledMethod(String source, Range modRange, Range tpRange, Range typeRange, String name, Range paramRange, Range throwsRange, int id) { + List l = new ArrayList<>(); + l.add(" public static\n "); + if (!modRange.isEmpty()) { + l.add(new RangeWrap(source, modRange)); + l.add(" "); + } + if (tpRange != null) { + l.add("<"); + l.add(new RangeWrap(source, tpRange)); + l.add("> "); + } + l.add(new RangeWrap(source, typeRange)); + l.add(" " + name + "(\n "); + if (paramRange != null) { + l.add(new RangeWrap(source, paramRange)); + } + l.add(") "); + if (throwsRange != null) { + l.add("throws "); + l.add(new RangeWrap(source, throwsRange)); + } + l.add(" {\n throw new jdk.internal.jshell.remote.RemoteResolutionException(" + id + ");\n}\n"); + return new CompoundWrap(l.toArray()); + } + + /** + * + * @param in + * @param rname + * @param rinit Initializer or null + * @param rdecl Type name and name + * @return + */ + public static Wrap varWrap(String source, Range rtype, String brackets, Range rname, Range rinit) { + RangeWrap wname = new RangeWrap(source, rname); + RangeWrap wtype = new RangeWrap(source, rtype); + Wrap wVarDecl = new VarDeclareWrap(wtype, brackets, wname); + Wrap wmeth; + + if (rinit == null) { + wmeth = new CompoundWrap(new NoWrap(" "), " return null;\n"); + } else { + RangeWrap winit = new RangeWrap(source, rinit); + // int x = y + // int x_ = y; return x = x_; + // decl + "_ = " + init ; + "return " + name + "=" + name + "_ ;" + wmeth = new CompoundWrap( + wtype, brackets + " ", wname, "_ =\n ", winit, semi(winit), + " return ", wname, " = ", wname, "_;\n" + ); + } + Wrap wInitMeth = new DoitMethodWrap(wmeth); + return new CompoundWrap(wVarDecl, wInitMeth); + } + + public static Wrap tempVarWrap(String source, String typename, String name) { + RangeWrap winit = new NoWrap(source); + // y + // return $1 = y; + // "return " + $1 + "=" + init ; + Wrap wmeth = new CompoundWrap("return " + name + " =\n ", winit, semi(winit)); + Wrap wInitMeth = new DoitMethodWrap(wmeth); + + String varDecl = " public static\n " + typename + " " + name + ";\n"; + return new CompoundWrap(varDecl, wInitMeth); + } + + public static Wrap importWrap(String source) { + return new NoWrap(source); + } + + public static Wrap classMemberWrap(String source) { + Wrap w = new NoWrap(source); + return new CompoundWrap(" public static\n ", w); + } + + private static int countLines(String s) { + return countLines(s, 0, s.length()); + } + + private static int countLines(String s, int from, int toEx) { + int cnt = 0; + int idx = from; + while ((idx = s.indexOf('\n', idx)) > 0) { + if (idx >= toEx) break; + ++cnt; + ++idx; + } + return cnt; + } + + public static final class Range { + final int begin; + final int end; + + Range(int begin, int end) { + this.begin = begin; + this.end = end; + } + + Range(String s) { + this.begin = 0; + this.end = s.length(); + } + + String part(String s) { + return s.substring(begin, end); + } + + int length() { + return end - begin; + } + + boolean isEmpty() { + return end == begin; + } + + void verify(String s) { + if (begin < 0 || end <= begin || end > s.length()) { + throw new InternalError("Bad Range: " + s + "[" + begin + "," + end + "]"); + } + } + + @Override + public String toString() { + return "Range[" + begin + "," + end + "]"; + } + } + + public static class CompoundWrap extends Wrap { + + final Object[] os; + final String wrapped; + final int snidxFirst; + final int snidxLast; + final int snlineFirst; + final int snlineLast; + + CompoundWrap(Object... os) { + this.os = os; + int sniFirst = Integer.MAX_VALUE; + int sniLast = Integer.MIN_VALUE; + int snlnFirst = Integer.MAX_VALUE; + int snlnLast = Integer.MIN_VALUE; + StringBuilder sb = new StringBuilder(); + for (Object o : os) { + if (o instanceof String) { + String s = (String) o; + sb.append(s); + } else if (o instanceof Wrap) { + Wrap w = (Wrap) o; + if (w.firstSnippetIndex() < sniFirst) { + sniFirst = w.firstSnippetIndex(); + } + if (w.lastSnippetIndex() > sniLast) { + sniLast = w.lastSnippetIndex(); + } + if (w.firstSnippetLine() < snlnFirst) { + snlnFirst = w.firstSnippetLine(); + } + if (w.lastSnippetLine() > snlnLast) { + snlnLast = w.lastSnippetLine(); + } + sb.append(w.wrapped()); + } else { + throw new InternalError("Bad object in CommoundWrap: " + o); + } + } + this.wrapped = sb.toString(); + this.snidxFirst = sniFirst; + this.snidxLast = sniLast; + this.snlineFirst = snlnFirst; + this.snlineLast = snlnLast; + } + + @Override + public String wrapped() { + return wrapped; + } + + @Override + public int snippetIndexToWrapIndex(int sni) { + int before = 0; + for (Object o : os) { + if (o instanceof String) { + String s = (String) o; + before += s.length(); + } else if (o instanceof Wrap) { + Wrap w = (Wrap) o; + if (sni >= w.firstSnippetIndex() && sni <= w.lastSnippetIndex()) { + return w.snippetIndexToWrapIndex(sni) + before; + } + before += w.wrapped().length(); + } + } + return 0; + } + + @Override + public int wrapIndexToSnippetIndex(int wi) { + int before = 0; + for (Object o : os) { + if (o instanceof String) { + String s = (String) o; + before += s.length(); + } else if (o instanceof Wrap) { + Wrap w = (Wrap) o; + int len = w.wrapped().length(); + if ((wi - before) <= len) { + //System.err.printf("Defer to wrap %s - wi: %d. before; %d -- %s >>> %s\n", + // w, wi, before, w.debugPos(wi - before), w.wrapped()); + return w.wrapIndexToSnippetIndex(wi - before); + } + before += len; + } + } + return lastSnippetIndex(); + } + + @Override + public int firstSnippetIndex() { + return snidxFirst; + } + + @Override + public int lastSnippetIndex() { + return snidxLast; + } + + @Override + public int snippetLineToWrapLine(int snline) { + int before = 0; + for (Object o : os) { + if (o instanceof String) { + String s = (String) o; + before += countLines(s); + } else if (o instanceof Wrap) { + Wrap w = (Wrap) o; + if (snline >= w.firstSnippetLine() && snline <= w.lastSnippetLine()) { + return w.snippetLineToWrapLine(snline) + before; + } + before += countLines(w.wrapped()); + } + } + return 0; + } + + @Override + public int wrapLineToSnippetLine(int wline) { + int before = 0; + for (Object o : os) { + if (o instanceof String) { + String s = (String) o; + before += countLines(s); + } else if (o instanceof Wrap) { + Wrap w = (Wrap) o; + int lns = countLines(w.wrapped()); + if ((wline - before) < lns) { + return w.wrapLineToSnippetLine(wline - before); + } + before += lns; + } + } + return 0; + } + + @Override + public int firstSnippetLine() { + return snlineFirst; + } + + @Override + public int lastSnippetLine() { + return snlineLast; + } + + + } + + private static class RangeWrap extends Wrap { + + final Range range; + final String wrapped; + final int firstSnline; + final int lastSnline; + + RangeWrap(String snippetSource, Range usedWithinSnippet) { + this.range = usedWithinSnippet; + this.wrapped = usedWithinSnippet.part(snippetSource); + usedWithinSnippet.verify(snippetSource); + this.firstSnline = countLines(snippetSource, 0, range.begin); + this.lastSnline = firstSnline + countLines(snippetSource, range.begin, range.end); + } + + @Override + public String wrapped() { + return wrapped; + } + + @Override + public int snippetIndexToWrapIndex(int sni) { + if (sni < range.begin) { + return 0; + } + if (sni > range.end) { + return range.length(); + } + return sni - range.begin; + } + + @Override + public int wrapIndexToSnippetIndex(int wi) { + if (wi < 0) { + return 0; // bad index + } + int max = range.length(); + if (wi > max) { + wi = max; + } + return wi + range.begin; + } + + @Override + public int firstSnippetIndex() { + return range.begin; + } + + @Override + public int lastSnippetIndex() { + return range.end; + } + + @Override + public int snippetLineToWrapLine(int snline) { + if (snline < firstSnline) { + return 0; + } + if (snline >= lastSnline) { + return lastSnline - firstSnline; + } + return snline - firstSnline; + } + + @Override + public int wrapLineToSnippetLine(int wline) { + if (wline < 0) { + return 0; // bad index + } + int max = lastSnline - firstSnline; + if (wline > max) { + wline = max; + } + return wline + firstSnline; + } + + @Override + public int firstSnippetLine() { + return firstSnline; + } + + @Override + public int lastSnippetLine() { + return lastSnline; + } + + } + + private static class NoWrap extends RangeWrap { + + NoWrap(String unit) { + super(unit, new Range(unit)); + } + } + + private static String semi(Wrap w) { + return semi(w.wrapped()); + } + + private static String semi(String s) { + return ((s.endsWith(";")) ? "\n" : ((s.endsWith(";\n")) ? "" : ";\n")); + } + + private static class DoitMethodWrap extends CompoundWrap { + + DoitMethodWrap(Wrap w) { + super(" public static Object " + DOIT_METHOD_NAME + "() throws Throwable {\n" + + " ", w, + " }\n"); + } + } + + private static class VarDeclareWrap extends CompoundWrap { + + VarDeclareWrap(Wrap wtype, String brackets, Wrap wname) { + super(" public static ", wtype, brackets + " ", wname, semi(wname)); + } + } +}