langtools/src/jdk.jshell/share/classes/jdk/jshell/Wrap.java
changeset 33362 65ec6de1d6b4
child 34752 9c262a013456
equal deleted inserted replaced
33361:1c96344ecd49 33362:65ec6de1d6b4
       
     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 package jdk.jshell;
       
    26 
       
    27 import java.util.ArrayList;
       
    28 import java.util.List;
       
    29 import static jdk.internal.jshell.remote.RemoteCodes.DOIT_METHOD_NAME;
       
    30 
       
    31 /**
       
    32  * Wrapping of source into Java methods, fields, etc.  All but outer layer
       
    33  * wrapping with imports and class.
       
    34  *
       
    35  * @author Robert Field
       
    36  */
       
    37 abstract class Wrap implements GeneralWrap {
       
    38 
       
    39     private static Wrap methodWrap(String prefix, String source, String suffix) {
       
    40         Wrap wunit = new NoWrap(source);
       
    41         return new DoitMethodWrap(new CompoundWrap(prefix, wunit, suffix));
       
    42     }
       
    43 
       
    44     public static Wrap methodWrap(String source) {
       
    45         return methodWrap("", source, semi(source) + "        return null;\n");
       
    46     }
       
    47 
       
    48     public static Wrap methodReturnWrap(String source) {
       
    49         return methodWrap("return ", source, semi(source));
       
    50     }
       
    51 
       
    52     public static Wrap methodUnreachableSemiWrap(String source) {
       
    53         return methodWrap("", source, semi(source));
       
    54     }
       
    55 
       
    56     public static Wrap methodUnreachableWrap(String source) {
       
    57         return methodWrap("", source, "");
       
    58     }
       
    59 
       
    60     public static Wrap corralledMethod(String source, Range modRange, Range tpRange, Range typeRange, String name, Range paramRange, Range throwsRange, int id) {
       
    61         List<Object> l = new ArrayList<>();
       
    62         l.add("    public static\n    ");
       
    63         if (!modRange.isEmpty()) {
       
    64             l.add(new RangeWrap(source, modRange));
       
    65             l.add(" ");
       
    66         }
       
    67         if (tpRange != null) {
       
    68             l.add("<");
       
    69             l.add(new RangeWrap(source, tpRange));
       
    70             l.add("> ");
       
    71         }
       
    72         l.add(new RangeWrap(source, typeRange));
       
    73         l.add(" " + name + "(\n        ");
       
    74         if (paramRange != null) {
       
    75             l.add(new RangeWrap(source, paramRange));
       
    76         }
       
    77         l.add(") ");
       
    78         if (throwsRange != null) {
       
    79             l.add("throws ");
       
    80             l.add(new RangeWrap(source, throwsRange));
       
    81         }
       
    82         l.add(" {\n        throw new jdk.internal.jshell.remote.RemoteResolutionException(" + id + ");\n}\n");
       
    83         return new CompoundWrap(l.toArray());
       
    84     }
       
    85 
       
    86     /**
       
    87      *
       
    88      * @param in
       
    89      * @param rname
       
    90      * @param rinit Initializer or null
       
    91      * @param rdecl Type name and name
       
    92      * @return
       
    93      */
       
    94     public static Wrap varWrap(String source, Range rtype, String brackets, Range rname, Range rinit) {
       
    95         RangeWrap wname = new RangeWrap(source, rname);
       
    96         RangeWrap wtype = new RangeWrap(source, rtype);
       
    97         Wrap wVarDecl = new VarDeclareWrap(wtype, brackets, wname);
       
    98         Wrap wmeth;
       
    99 
       
   100         if (rinit == null) {
       
   101             wmeth = new CompoundWrap(new NoWrap(" "), "   return null;\n");
       
   102         } else {
       
   103             RangeWrap winit = new RangeWrap(source, rinit);
       
   104         // int x = y
       
   105             // int x_ = y; return x = x_;
       
   106             // decl + "_ = " + init ; + "return " + name + "=" + name + "_ ;"
       
   107             wmeth = new CompoundWrap(
       
   108                     wtype, brackets + " ", wname, "_ =\n        ", winit, semi(winit),
       
   109                     "        return ", wname, " = ", wname, "_;\n"
       
   110             );
       
   111         }
       
   112         Wrap wInitMeth = new DoitMethodWrap(wmeth);
       
   113         return new CompoundWrap(wVarDecl, wInitMeth);
       
   114     }
       
   115 
       
   116     public static Wrap tempVarWrap(String source, String typename, String name) {
       
   117         RangeWrap winit = new NoWrap(source);
       
   118         // y
       
   119         // return $1 = y;
       
   120         // "return " + $1 + "=" + init ;
       
   121         Wrap wmeth = new CompoundWrap("return " + name + " =\n        ", winit, semi(winit));
       
   122         Wrap wInitMeth = new DoitMethodWrap(wmeth);
       
   123 
       
   124         String varDecl = "    public static\n    " + typename + " " + name + ";\n";
       
   125         return new CompoundWrap(varDecl, wInitMeth);
       
   126     }
       
   127 
       
   128     public static Wrap importWrap(String source) {
       
   129         return new NoWrap(source);
       
   130     }
       
   131 
       
   132     public static Wrap classMemberWrap(String source) {
       
   133         Wrap w = new NoWrap(source);
       
   134         return new CompoundWrap("    public static\n    ", w);
       
   135     }
       
   136 
       
   137     private static int countLines(String s) {
       
   138         return countLines(s, 0, s.length());
       
   139     }
       
   140 
       
   141     private static int countLines(String s, int from, int toEx) {
       
   142         int cnt = 0;
       
   143         int idx = from;
       
   144         while ((idx = s.indexOf('\n', idx)) > 0) {
       
   145             if (idx >= toEx) break;
       
   146             ++cnt;
       
   147             ++idx;
       
   148         }
       
   149         return cnt;
       
   150     }
       
   151 
       
   152     public static final class Range {
       
   153         final int begin;
       
   154         final int end;
       
   155 
       
   156         Range(int begin, int end) {
       
   157             this.begin = begin;
       
   158             this.end = end;
       
   159         }
       
   160 
       
   161         Range(String s) {
       
   162             this.begin = 0;
       
   163             this.end = s.length();
       
   164         }
       
   165 
       
   166         String part(String s) {
       
   167             return s.substring(begin, end);
       
   168         }
       
   169 
       
   170         int length() {
       
   171             return end - begin;
       
   172         }
       
   173 
       
   174         boolean isEmpty() {
       
   175             return end == begin;
       
   176         }
       
   177 
       
   178         void verify(String s) {
       
   179             if (begin < 0 || end <= begin || end > s.length()) {
       
   180                 throw new InternalError("Bad Range: " + s + "[" + begin + "," + end + "]");
       
   181             }
       
   182         }
       
   183 
       
   184         @Override
       
   185         public String toString() {
       
   186             return "Range[" + begin + "," + end + "]";
       
   187         }
       
   188     }
       
   189 
       
   190     public static class CompoundWrap extends Wrap {
       
   191 
       
   192         final Object[] os;
       
   193         final String wrapped;
       
   194         final int snidxFirst;
       
   195         final int snidxLast;
       
   196         final int snlineFirst;
       
   197         final int snlineLast;
       
   198 
       
   199         CompoundWrap(Object... os) {
       
   200             this.os = os;
       
   201             int sniFirst = Integer.MAX_VALUE;
       
   202             int sniLast = Integer.MIN_VALUE;
       
   203             int snlnFirst = Integer.MAX_VALUE;
       
   204             int snlnLast = Integer.MIN_VALUE;
       
   205             StringBuilder sb = new StringBuilder();
       
   206             for (Object o : os) {
       
   207                 if (o instanceof String) {
       
   208                     String s = (String) o;
       
   209                     sb.append(s);
       
   210                 } else if (o instanceof Wrap) {
       
   211                     Wrap w = (Wrap) o;
       
   212                     if (w.firstSnippetIndex() < sniFirst) {
       
   213                         sniFirst = w.firstSnippetIndex();
       
   214                     }
       
   215                     if (w.lastSnippetIndex() > sniLast) {
       
   216                         sniLast = w.lastSnippetIndex();
       
   217                     }
       
   218                     if (w.firstSnippetLine() < snlnFirst) {
       
   219                         snlnFirst = w.firstSnippetLine();
       
   220                     }
       
   221                     if (w.lastSnippetLine() > snlnLast) {
       
   222                         snlnLast = w.lastSnippetLine();
       
   223                     }
       
   224                     sb.append(w.wrapped());
       
   225                 } else {
       
   226                     throw new InternalError("Bad object in CommoundWrap: " + o);
       
   227                 }
       
   228             }
       
   229             this.wrapped = sb.toString();
       
   230             this.snidxFirst = sniFirst;
       
   231             this.snidxLast = sniLast;
       
   232             this.snlineFirst = snlnFirst;
       
   233             this.snlineLast = snlnLast;
       
   234         }
       
   235 
       
   236         @Override
       
   237         public String wrapped() {
       
   238             return wrapped;
       
   239         }
       
   240 
       
   241         @Override
       
   242         public int snippetIndexToWrapIndex(int sni) {
       
   243             int before = 0;
       
   244             for (Object o : os) {
       
   245                 if (o instanceof String) {
       
   246                     String s = (String) o;
       
   247                     before += s.length();
       
   248                 } else if (o instanceof Wrap) {
       
   249                     Wrap w = (Wrap) o;
       
   250                     if (sni >= w.firstSnippetIndex() && sni <= w.lastSnippetIndex()) {
       
   251                         return w.snippetIndexToWrapIndex(sni) + before;
       
   252                     }
       
   253                     before += w.wrapped().length();
       
   254                 }
       
   255             }
       
   256             return 0;
       
   257         }
       
   258 
       
   259         @Override
       
   260         public int wrapIndexToSnippetIndex(int wi) {
       
   261             int before = 0;
       
   262             for (Object o : os) {
       
   263                 if (o instanceof String) {
       
   264                     String s = (String) o;
       
   265                     before += s.length();
       
   266                 } else if (o instanceof Wrap) {
       
   267                     Wrap w = (Wrap) o;
       
   268                     int len = w.wrapped().length();
       
   269                     if ((wi - before) <= len) {
       
   270                         //System.err.printf("Defer to wrap %s - wi: %d. before; %d   -- %s  >>> %s\n",
       
   271                         //        w, wi, before, w.debugPos(wi - before), w.wrapped());
       
   272                         return w.wrapIndexToSnippetIndex(wi - before);
       
   273                     }
       
   274                     before += len;
       
   275                 }
       
   276             }
       
   277             return lastSnippetIndex();
       
   278         }
       
   279 
       
   280         @Override
       
   281         public int firstSnippetIndex() {
       
   282             return snidxFirst;
       
   283         }
       
   284 
       
   285         @Override
       
   286         public int lastSnippetIndex() {
       
   287             return snidxLast;
       
   288         }
       
   289 
       
   290         @Override
       
   291         public int snippetLineToWrapLine(int snline) {
       
   292             int before = 0;
       
   293             for (Object o : os) {
       
   294                 if (o instanceof String) {
       
   295                     String s = (String) o;
       
   296                     before += countLines(s);
       
   297                 } else if (o instanceof Wrap) {
       
   298                     Wrap w = (Wrap) o;
       
   299                     if (snline >= w.firstSnippetLine() && snline <= w.lastSnippetLine()) {
       
   300                         return w.snippetLineToWrapLine(snline) + before;
       
   301                     }
       
   302                     before += countLines(w.wrapped());
       
   303                 }
       
   304             }
       
   305             return 0;
       
   306         }
       
   307 
       
   308         @Override
       
   309         public int wrapLineToSnippetLine(int wline) {
       
   310             int before = 0;
       
   311             for (Object o : os) {
       
   312                 if (o instanceof String) {
       
   313                     String s = (String) o;
       
   314                     before += countLines(s);
       
   315                 } else if (o instanceof Wrap) {
       
   316                     Wrap w = (Wrap) o;
       
   317                     int lns = countLines(w.wrapped());
       
   318                     if ((wline - before) < lns) {
       
   319                         return w.wrapLineToSnippetLine(wline - before);
       
   320                     }
       
   321                     before += lns;
       
   322                 }
       
   323             }
       
   324             return 0;
       
   325         }
       
   326 
       
   327         @Override
       
   328         public int firstSnippetLine() {
       
   329             return snlineFirst;
       
   330         }
       
   331 
       
   332         @Override
       
   333         public int lastSnippetLine() {
       
   334             return snlineLast;
       
   335         }
       
   336 
       
   337 
       
   338     }
       
   339 
       
   340     private static class RangeWrap extends Wrap {
       
   341 
       
   342         final Range range;
       
   343         final String wrapped;
       
   344         final int firstSnline;
       
   345         final int lastSnline;
       
   346 
       
   347         RangeWrap(String snippetSource, Range usedWithinSnippet) {
       
   348             this.range = usedWithinSnippet;
       
   349             this.wrapped = usedWithinSnippet.part(snippetSource);
       
   350             usedWithinSnippet.verify(snippetSource);
       
   351             this.firstSnline = countLines(snippetSource, 0, range.begin);
       
   352             this.lastSnline = firstSnline + countLines(snippetSource, range.begin, range.end);
       
   353         }
       
   354 
       
   355         @Override
       
   356         public String wrapped() {
       
   357             return wrapped;
       
   358         }
       
   359 
       
   360         @Override
       
   361         public int snippetIndexToWrapIndex(int sni) {
       
   362             if (sni < range.begin) {
       
   363                 return 0;
       
   364             }
       
   365             if (sni > range.end) {
       
   366                 return range.length();
       
   367             }
       
   368             return sni - range.begin;
       
   369         }
       
   370 
       
   371         @Override
       
   372         public int wrapIndexToSnippetIndex(int wi) {
       
   373             if (wi < 0) {
       
   374                 return 0; // bad index
       
   375             }
       
   376             int max = range.length();
       
   377             if (wi > max) {
       
   378                 wi = max;
       
   379             }
       
   380             return wi + range.begin;
       
   381         }
       
   382 
       
   383         @Override
       
   384         public int firstSnippetIndex() {
       
   385             return range.begin;
       
   386         }
       
   387 
       
   388         @Override
       
   389         public int lastSnippetIndex() {
       
   390             return range.end;
       
   391         }
       
   392 
       
   393         @Override
       
   394         public int snippetLineToWrapLine(int snline) {
       
   395             if (snline < firstSnline) {
       
   396                 return 0;
       
   397             }
       
   398             if (snline >= lastSnline) {
       
   399                 return lastSnline - firstSnline;
       
   400             }
       
   401             return snline - firstSnline;
       
   402         }
       
   403 
       
   404         @Override
       
   405         public int wrapLineToSnippetLine(int wline) {
       
   406             if (wline < 0) {
       
   407                 return 0; // bad index
       
   408             }
       
   409             int max = lastSnline - firstSnline;
       
   410             if (wline > max) {
       
   411                 wline = max;
       
   412             }
       
   413             return wline + firstSnline;
       
   414         }
       
   415 
       
   416         @Override
       
   417         public int firstSnippetLine() {
       
   418             return firstSnline;
       
   419         }
       
   420 
       
   421         @Override
       
   422         public int lastSnippetLine() {
       
   423             return lastSnline;
       
   424         }
       
   425 
       
   426     }
       
   427 
       
   428     private static class NoWrap extends RangeWrap {
       
   429 
       
   430         NoWrap(String unit) {
       
   431             super(unit, new Range(unit));
       
   432         }
       
   433     }
       
   434 
       
   435     private static String semi(Wrap w) {
       
   436         return semi(w.wrapped());
       
   437     }
       
   438 
       
   439     private static String semi(String s) {
       
   440         return ((s.endsWith(";")) ? "\n" : ((s.endsWith(";\n")) ? "" : ";\n"));
       
   441     }
       
   442 
       
   443     private static class DoitMethodWrap extends CompoundWrap {
       
   444 
       
   445         DoitMethodWrap(Wrap w) {
       
   446             super("    public static Object " + DOIT_METHOD_NAME + "() throws Throwable {\n"
       
   447                     + "        ", w,
       
   448                     "    }\n");
       
   449         }
       
   450     }
       
   451 
       
   452     private static class VarDeclareWrap extends CompoundWrap {
       
   453 
       
   454         VarDeclareWrap(Wrap wtype, String brackets, Wrap wname) {
       
   455             super("    public static ", wtype, brackets + " ", wname, semi(wname));
       
   456         }
       
   457     }
       
   458 }