1 /* 2 * Copyright (c) 2015, 2019, 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 26 package jdk.jshell; 27 28 import java.util.ArrayList; 29 import java.util.Arrays; 30 import java.util.List; 31 import static java.util.stream.Collectors.joining; 32 import static jdk.jshell.Util.DOIT_METHOD_NAME; 33 34 /** 35 * Wrapping of source into Java methods, fields, etc. All but outer layer 36 * wrapping with imports and class. 37 */ 38 abstract class Wrap implements GeneralWrap { 39 methodWrap(String prefix, String source, String suffix)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 methodWrap(String source)45 public static Wrap methodWrap(String source) { 46 return methodWrap("", source, semi(source) + " return null;\n"); 47 } 48 methodReturnWrap(String source)49 public static Wrap methodReturnWrap(String source) { 50 return methodWrap("return ", source, semi(source)); 51 } 52 methodUnreachableSemiWrap(String source)53 public static Wrap methodUnreachableSemiWrap(String source) { 54 return methodWrap("", source, semi(source)); 55 } 56 methodUnreachableWrap(String source)57 public static Wrap methodUnreachableWrap(String source) { 58 return methodWrap("", source, ""); 59 } 60 indent(int n)61 private static String indent(int n) { 62 return " ".substring(0, n * 4); 63 } 64 nlindent(int n)65 private static String nlindent(int n) { 66 return "\n" + indent(n); 67 } 68 69 /**Create a stub of a compilable representation of a variable snippet. 70 * The variable is always represented by a field. If the variable 71 * in the snippet has an initializer, the field is initialized by 72 * calling the DOIT_METHOD_NAME method. 73 * 74 * In some cases, the real inferred type of the variable may be non-denotable 75 * (e.g. intersection types). The declared type of the field must always 76 * be denotable (i.e. such that it can be written into the classfile), but 77 * if the real type is potentially non-denotable, the {@code enhanced} parameter 78 * must be true. 79 * 80 * @param source the snippet's masked source code 81 * @param wtype variable's denotable type suitable for field declaration 82 * @param brackets any [] that should be appended to the type 83 * @param wname a wrap of the source that denotes the name of the variable 84 * @param winit Initializer or null 85 * @param enhanced if the real inferred type of the variable is potentially 86 * non-denotable, this must be true 87 * @return a Wrap that declares the given variable, potentially with 88 * an initialization method 89 */ varWrap(String source, Wrap wtype, String brackets, Wrap wname, Wrap winit, boolean enhanced, Wrap anonDeclareWrap)90 public static Wrap varWrap(String source, Wrap wtype, String brackets, 91 Wrap wname, Wrap winit, boolean enhanced, 92 Wrap anonDeclareWrap) { 93 List<Object> components = new ArrayList<>(); 94 components.add(new VarDeclareWrap(wtype, brackets, wname)); 95 Wrap wmeth; 96 97 if (winit == null) { 98 wmeth = new CompoundWrap(new NoWrap(" "), " return null;\n"); 99 } else { 100 // int x = y 101 if (enhanced) { 102 // private static <Z> Z do_itAux() { 103 // wtype x_ = y; 104 // @SuppressWarnings("unchecked") 105 // Z x__ = (Z) x_; 106 // return x__; 107 // } 108 // in do_it method: 109 //return do_itAux(); 110 //find an unused name: 111 String scratchName = "$"; 112 while (winit.wrapped().contains(scratchName)) { 113 scratchName += "$"; 114 } 115 Wrap waux = new CompoundWrap( 116 " private static <" + scratchName + "> " + scratchName +" ", DOIT_METHOD_NAME + "Aux", "() throws Throwable {\n", 117 wtype, brackets + " ", scratchName, "_ =\n ", winit, semi(winit), 118 " @SuppressWarnings(\"unchecked\") ", scratchName, " ", scratchName, "__ = (", scratchName, ")", scratchName, "_;\n", 119 " return ", scratchName, "__;\n", 120 "}" 121 ); 122 components.add(waux); 123 wmeth = new CompoundWrap( 124 " return ", wname, " = ", DOIT_METHOD_NAME + "Aux", "();\n" 125 ); 126 } else { 127 // int x_ = y; return x = x_; 128 // decl + "_ = " + init ; + "return " + name + "= " + name + "_ ;" 129 wmeth = new CompoundWrap( 130 wtype, brackets + " ", wname, "_ =\n ", winit, semi(winit), 131 " return ", wname, " = ", wname, "_;\n" 132 ); 133 } 134 } 135 components.add(new DoitMethodWrap(wmeth)); 136 if (anonDeclareWrap != null) { 137 components.add(anonDeclareWrap); 138 } 139 return new CompoundWrap(components.toArray()); 140 } 141 tempVarWrap(String source, String typename, String name, Wrap anonDeclareWrap)142 public static Wrap tempVarWrap(String source, String typename, String name, Wrap anonDeclareWrap) { 143 RangeWrap winit = new NoWrap(source); 144 // y 145 // return $1 = y; 146 // "return " + $1 + "=" + init ; 147 Wrap wmeth = new CompoundWrap("return " + name + " =\n ", winit, semi(winit)); 148 Wrap wInitMeth = new DoitMethodWrap(wmeth); 149 150 String varDecl = " public static\n " + typename + " " + name + ";\n"; 151 return anonDeclareWrap != null ? new CompoundWrap(varDecl, wInitMeth, anonDeclareWrap) 152 : new CompoundWrap(varDecl, wInitMeth); 153 } 154 simpleWrap(String source)155 public static Wrap simpleWrap(String source) { 156 return new NoWrap(source); 157 } 158 identityWrap(String source)159 public static Wrap identityWrap(String source) { 160 return new NoWrap(source); 161 } 162 rangeWrap(String source, Range range)163 public static Wrap rangeWrap(String source, Range range) { 164 return new RangeWrap(source, range); 165 } 166 classMemberWrap(String source)167 public static Wrap classMemberWrap(String source) { 168 Wrap w = new NoWrap(source); 169 return new CompoundWrap(" public static\n ", w); 170 } 171 countLines(String s)172 private static int countLines(String s) { 173 return countLines(s, 0, s.length()); 174 } 175 countLines(String s, int from, int toEx)176 private static int countLines(String s, int from, int toEx) { 177 int cnt = 0; 178 int idx = from; 179 while ((idx = s.indexOf('\n', idx)) > 0) { 180 if (idx >= toEx) break; 181 ++cnt; 182 ++idx; 183 } 184 return cnt; 185 } 186 187 public static final class Range { 188 final int begin; 189 final int end; // exclusive 190 Range(int begin, int end)191 Range(int begin, int end) { 192 this.begin = begin; 193 this.end = end; 194 } 195 Range(String s)196 Range(String s) { 197 this.begin = 0; 198 this.end = s.length(); 199 } 200 part(String s)201 String part(String s) { 202 return s.substring(begin, end); 203 } 204 length()205 int length() { 206 return end - begin; 207 } 208 isEmpty()209 boolean isEmpty() { 210 return end == begin; 211 } 212 verify(String s)213 void verify(String s) { 214 if (begin < 0 || end <= begin || end > s.length()) { 215 throw new InternalError("Bad Range: " + s + "[" + begin + "," + end + "]"); 216 } 217 } 218 219 @Override toString()220 public String toString() { 221 return "Range[" + begin + "," + end + ")"; 222 } 223 } 224 225 public static class CompoundWrap extends Wrap { 226 227 final Object[] os; 228 final String wrapped; 229 final int snidxFirst; 230 final int snidxLast; 231 final int snlineFirst; 232 final int snlineLast; 233 CompoundWrap(Object... os)234 CompoundWrap(Object... os) { 235 this.os = os; 236 int sniFirst = Integer.MAX_VALUE; 237 int sniLast = Integer.MIN_VALUE; 238 int snlnFirst = Integer.MAX_VALUE; 239 int snlnLast = Integer.MIN_VALUE; 240 StringBuilder sb = new StringBuilder(); 241 for (Object o : os) { 242 if (o instanceof String) { 243 String s = (String) o; 244 sb.append(s); 245 } else if (o instanceof Wrap) { 246 Wrap w = (Wrap) o; 247 if (w.firstSnippetIndex() < sniFirst) { 248 sniFirst = w.firstSnippetIndex(); 249 } 250 if (w.lastSnippetIndex() > sniLast) { 251 sniLast = w.lastSnippetIndex(); 252 } 253 if (w.firstSnippetLine() < snlnFirst) { 254 snlnFirst = w.firstSnippetLine(); 255 } 256 if (w.lastSnippetLine() > snlnLast) { 257 snlnLast = w.lastSnippetLine(); 258 } 259 sb.append(w.wrapped()); 260 } else { 261 throw new InternalError("Bad object in CommoundWrap: " + o); 262 } 263 } 264 this.wrapped = sb.toString(); 265 this.snidxFirst = sniFirst; 266 this.snidxLast = sniLast; 267 this.snlineFirst = snlnFirst; 268 this.snlineLast = snlnLast; 269 } 270 271 @Override wrapped()272 public String wrapped() { 273 return wrapped; 274 } 275 276 @Override snippetIndexToWrapIndex(int sni)277 public int snippetIndexToWrapIndex(int sni) { 278 int before = 0; 279 for (Object o : os) { 280 if (o instanceof String) { 281 String s = (String) o; 282 before += s.length(); 283 } else if (o instanceof Wrap) { 284 Wrap w = (Wrap) o; 285 if (sni >= w.firstSnippetIndex() && sni < w.lastSnippetIndex()) { 286 int wwi = w.snippetIndexToWrapIndex(sni); 287 debugWrap("\nCommoundWrap.snippetIndexToWrapIndex: SnippetIndex(%d) -> WrapIndex(%d + %d = %d)" 288 + "\n === %s", 289 sni, wwi, before, wwi + before, wrapped()); 290 return wwi + before; 291 } 292 before += w.wrapped().length(); 293 } 294 } 295 return 0; 296 } 297 wrapIndexToWrap(long wi)298 Wrap wrapIndexToWrap(long wi) { 299 int before = 0; 300 Wrap w = null; 301 for (Object o : os) { 302 if (o instanceof String) { 303 String s = (String) o; 304 before += s.length(); 305 } else if (o instanceof Wrap) { 306 w = (Wrap) o; 307 int len = w.wrapped().length(); 308 if ((wi - before) <= len) { 309 debugWrap("CommoundWrap.wrapIndexToWrap: Defer to wrap %s - wi: %d. before; %d >>> %s\n", 310 w, wi, before, w.wrapped()); 311 return w; 312 } 313 before += len; 314 } 315 } 316 return w; 317 } 318 319 @Override wrapIndexToSnippetIndex(int wi)320 public int wrapIndexToSnippetIndex(int wi) { 321 int before = 0; 322 for (Object o : os) { 323 if (o instanceof String) { 324 String s = (String) o; 325 before += s.length(); 326 } else if (o instanceof Wrap) { 327 Wrap w = (Wrap) o; 328 int len = w.wrapped().length(); 329 if ((wi - before) <= len) { 330 int si = w.wrapIndexToSnippetIndex(wi - before); 331 debugWrap("\nCommoundWrap.wrapIndexToSnippetIndex: WrapIndex(%d) -> SnippetIndex(%d)\n", 332 wi, si); 333 return si; 334 } 335 before += len; 336 } 337 } 338 return lastSnippetIndex(); 339 } 340 341 @Override firstSnippetIndex()342 public int firstSnippetIndex() { 343 return snidxFirst; 344 } 345 346 @Override lastSnippetIndex()347 public int lastSnippetIndex() { 348 return snidxLast; 349 } 350 351 @Override snippetLineToWrapLine(int snline)352 public int snippetLineToWrapLine(int snline) { 353 int before = 0; 354 for (Object o : os) { 355 if (o instanceof String) { 356 String s = (String) o; 357 before += countLines(s); 358 } else if (o instanceof Wrap) { 359 Wrap w = (Wrap) o; 360 if (snline >= w.firstSnippetLine() && snline <= w.lastSnippetLine()) { 361 return w.snippetLineToWrapLine(snline) + before; 362 } 363 before += countLines(w.wrapped()); 364 } 365 } 366 return 0; 367 } 368 wrapLineToWrap(int wline)369 Wrap wrapLineToWrap(int wline) { 370 int before = 0; 371 Wrap w = null; 372 for (Object o : os) { 373 if (o instanceof String) { 374 String s = (String) o; 375 before += countLines(s); 376 } else if (o instanceof Wrap) { 377 w = (Wrap) o; 378 int lns = countLines(w.wrapped()); 379 if ((wline - before) <= lns) { 380 return w; 381 } 382 before += lns; 383 } 384 } 385 return w; 386 } 387 388 @Override wrapLineToSnippetLine(int wline)389 public int wrapLineToSnippetLine(int wline) { 390 int before = 0; 391 for (Object o : os) { 392 if (o instanceof String) { 393 String s = (String) o; 394 before += countLines(s); 395 } else if (o instanceof Wrap) { 396 Wrap w = (Wrap) o; 397 int lns = countLines(w.wrapped()); 398 if ((wline - before) <= lns) { 399 return w.wrapLineToSnippetLine(wline - before); 400 } 401 before += lns; 402 } 403 } 404 return 0; 405 } 406 407 @Override firstSnippetLine()408 public int firstSnippetLine() { 409 return snlineFirst; 410 } 411 412 @Override lastSnippetLine()413 public int lastSnippetLine() { 414 return snlineLast; 415 } 416 417 @Override toString()418 public String toString() { 419 return "CompoundWrap(" + Arrays.stream(os) 420 .map(o -> (o instanceof String) 421 ? "\"" + o + "\"" 422 : o.toString()) 423 .collect(joining(",")) 424 + ")"; 425 } 426 } 427 428 static class RangeWrap extends Wrap { 429 430 final Range range; 431 final String wrapped; // The snippet portion of the source 432 final int firstSnline; // Line count to start of snippet portion 433 final int lastSnline; // Line count to end of snippet portion 434 RangeWrap(String snippetSource, Range usedWithinSnippet)435 RangeWrap(String snippetSource, Range usedWithinSnippet) { 436 this.range = usedWithinSnippet; 437 this.wrapped = usedWithinSnippet.part(snippetSource); 438 usedWithinSnippet.verify(snippetSource); 439 this.firstSnline = countLines(snippetSource, 0, range.begin); 440 this.lastSnline = firstSnline + countLines(snippetSource, range.begin, range.end); 441 } 442 443 @Override wrapped()444 public String wrapped() { 445 return wrapped; 446 } 447 448 @Override snippetIndexToWrapIndex(int sni)449 public int snippetIndexToWrapIndex(int sni) { 450 if (sni < range.begin) { 451 debugWrap("\nRangeWrap.snippetIndexToWrapIndex: ERR before SnippetIndex(%d) -> WrapIndex(%d + %d = %d)\n", 452 sni, 0); 453 return 0; 454 } 455 if (sni > range.end) { 456 debugWrap("\nRangeWrap.snippetIndexToWrapIndex: ERR after SnippetIndex(%d) -> WrapIndex(%d + %d = %d)\n", 457 sni, range.length()); 458 return range.length(); 459 } 460 int wi = sni - range.begin; 461 debugWrap("\nRangeWrap.snippetIndexToWrapIndex: SnippetIndex(%d) -> WrapIndex(%d + %d = %d)" 462 + "\n === %s", 463 sni, sni, range.begin, sni - range.begin, wrapped()); 464 return wi; 465 } 466 467 @Override wrapIndexToSnippetIndex(int wi)468 public int wrapIndexToSnippetIndex(int wi) { 469 if (wi < 0) { 470 debugWrap("\nRangeWrap.wrapIndexToSnippetIndex: ERR before WrapIndex(%d) -> SnippetIndex(%d)\n", 471 wi, 0); 472 return 0; // bad index 473 } 474 int max = range.length(); 475 if (wi > max) { 476 debugWrap("\nRangeWrap.wrapIndexToSnippetIndex: ERR after WrapIndex(%d) -> SnippetIndex(%d)\n", 477 wi, max + range.begin); 478 return max + range.begin; 479 } 480 int sni = wi + range.begin; 481 debugWrap("\nRangeWrap.wrapIndexToSnippetIndex: WrapIndex(%d) -> SnippetIndex(%d)\n", 482 wi, sni); 483 return sni; 484 } 485 486 @Override firstSnippetIndex()487 public int firstSnippetIndex() { 488 return range.begin; 489 } 490 491 @Override lastSnippetIndex()492 public int lastSnippetIndex() { 493 return range.end; 494 } 495 496 @Override snippetLineToWrapLine(int snline)497 public int snippetLineToWrapLine(int snline) { 498 if (snline < firstSnline) { 499 return 0; 500 } 501 if (snline >= lastSnline) { 502 return lastSnline - firstSnline; 503 } 504 return snline - firstSnline; 505 } 506 507 @Override wrapLineToSnippetLine(int wline)508 public int wrapLineToSnippetLine(int wline) { 509 if (wline < 0) { 510 return 0; // bad index 511 } 512 int max = lastSnline - firstSnline; 513 if (wline > max) { 514 wline = max; 515 } 516 return wline + firstSnline; 517 } 518 519 @Override firstSnippetLine()520 public int firstSnippetLine() { 521 return firstSnline; 522 } 523 524 @Override lastSnippetLine()525 public int lastSnippetLine() { 526 return lastSnline; 527 } 528 529 @Override toString()530 public String toString() { 531 return "RangeWrap(" + range + ")"; 532 } 533 } 534 535 private static class NoWrap extends RangeWrap { 536 NoWrap(String unit)537 NoWrap(String unit) { 538 super(unit, new Range(unit)); 539 } 540 } 541 semi(Wrap w)542 private static String semi(Wrap w) { 543 return semi(w.wrapped()); 544 } 545 semi(String s)546 private static String semi(String s) { 547 return ((s.endsWith(";")) ? "\n" : ((s.endsWith(";\n")) ? "" : ";\n")); 548 } 549 550 private static class DoitMethodWrap extends CompoundWrap { 551 DoitMethodWrap(Wrap w)552 DoitMethodWrap(Wrap w) { 553 super(" public static Object " + DOIT_METHOD_NAME + "() throws Throwable {\n" 554 + " ", w, 555 " }\n"); 556 } 557 } 558 559 private static class VarDeclareWrap extends CompoundWrap { 560 VarDeclareWrap(Wrap wtype, String brackets, Wrap wname)561 VarDeclareWrap(Wrap wtype, String brackets, Wrap wname) { 562 super(" public static ", wtype, brackets + " ", wname, semi(wname)); 563 } 564 } 565 debugWrap(String format, Object... args)566 void debugWrap(String format, Object... args) { 567 //System.err.printf(format, args); 568 //state.debug(this, InternalDebugControl.DBG_WRAP, format, args); 569 } 570 } 571