langtools/src/jdk.jshell/share/classes/jdk/jshell/Wrap.java
changeset 33362 65ec6de1d6b4
child 34752 9c262a013456
--- /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<Object> 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));
+        }
+    }
+}