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