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