Wrap.java revision 3062:15bdc18525ff
1238384Sjkim/* 2238384Sjkim * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. 3238384Sjkim * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4238384Sjkim * 5238384Sjkim * This code is free software; you can redistribute it and/or modify it 6238384Sjkim * under the terms of the GNU General Public License version 2 only, as 7238384Sjkim * published by the Free Software Foundation. Oracle designates this 8238384Sjkim * particular file as subject to the "Classpath" exception as provided 9238384Sjkim * by Oracle in the LICENSE file that accompanied this code. 10238384Sjkim * 11238384Sjkim * This code is distributed in the hope that it will be useful, but WITHOUT 12238384Sjkim * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13238384Sjkim * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14238384Sjkim * version 2 for more details (a copy is included in the LICENSE file that 15238384Sjkim * accompanied this code). 16238384Sjkim * 17238384Sjkim * You should have received a copy of the GNU General Public License version 18238384Sjkim * 2 along with this work; if not, write to the Free Software Foundation, 19238384Sjkim * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20238384Sjkim * 21238384Sjkim * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22238384Sjkim * or visit www.oracle.com if you need additional information or have any 23238384Sjkim * questions. 24238384Sjkim */ 25238384Sjkimpackage jdk.jshell; 26238384Sjkim 27238384Sjkimimport java.util.ArrayList; 28238384Sjkimimport java.util.List; 29238384Sjkimimport static jdk.internal.jshell.remote.RemoteCodes.DOIT_METHOD_NAME; 30238384Sjkim 31238384Sjkim/** 32238384Sjkim * Wrapping of source into Java methods, fields, etc. All but outer layer 33238384Sjkim * wrapping with imports and class. 34238384Sjkim * 35238384Sjkim * @author Robert Field 36238384Sjkim */ 37238384Sjkimabstract class Wrap implements GeneralWrap { 38238384Sjkim 39238384Sjkim private static Wrap methodWrap(String prefix, String source, String suffix) { 40238384Sjkim Wrap wunit = new NoWrap(source); 41238384Sjkim return new DoitMethodWrap(new CompoundWrap(prefix, wunit, suffix)); 42238384Sjkim } 43238384Sjkim 44238384Sjkim public static Wrap methodWrap(String source) { 45238384Sjkim return methodWrap("", source, semi(source) + " return null;\n"); 46238384Sjkim } 47238384Sjkim 48238384Sjkim public static Wrap methodReturnWrap(String source) { 49238384Sjkim return methodWrap("return ", source, semi(source)); 50238384Sjkim } 51238384Sjkim 52238384Sjkim public static Wrap methodUnreachableSemiWrap(String source) { 53238384Sjkim return methodWrap("", source, semi(source)); 54238384Sjkim } 55238384Sjkim 56238384Sjkim public static Wrap methodUnreachableWrap(String source) { 57238384Sjkim return methodWrap("", source, ""); 58238384Sjkim } 59238384Sjkim 60238384Sjkim public static Wrap corralledMethod(String source, Range modRange, Range tpRange, Range typeRange, String name, Range paramRange, Range throwsRange, int id) { 61238384Sjkim List<Object> l = new ArrayList<>(); 62238384Sjkim l.add(" public static\n "); 63238384Sjkim if (!modRange.isEmpty()) { 64238384Sjkim l.add(new RangeWrap(source, modRange)); 65238384Sjkim l.add(" "); 66238384Sjkim } 67238384Sjkim if (tpRange != null) { 68238384Sjkim l.add("<"); 69238384Sjkim l.add(new RangeWrap(source, tpRange)); 70238384Sjkim l.add("> "); 71238384Sjkim } 72238384Sjkim l.add(new RangeWrap(source, typeRange)); 73238384Sjkim l.add(" " + name + "(\n "); 74238384Sjkim if (paramRange != null) { 75238384Sjkim l.add(new RangeWrap(source, paramRange)); 76238384Sjkim } 77238384Sjkim l.add(") "); 78238384Sjkim if (throwsRange != null) { 79238384Sjkim l.add("throws "); 80238384Sjkim l.add(new RangeWrap(source, throwsRange)); 81238384Sjkim } 82238384Sjkim l.add(" {\n throw new jdk.internal.jshell.remote.RemoteResolutionException(" + id + ");\n}\n"); 83238384Sjkim return new CompoundWrap(l.toArray()); 84238384Sjkim } 85238384Sjkim 86238384Sjkim /** 87238384Sjkim * 88238384Sjkim * @param in 89238384Sjkim * @param rname 90238384Sjkim * @param rinit Initializer or null 91238384Sjkim * @param rdecl Type name and name 92238384Sjkim * @return 93238384Sjkim */ 94238384Sjkim public static Wrap varWrap(String source, Range rtype, String brackets, Range rname, Range rinit) { 95238384Sjkim RangeWrap wname = new RangeWrap(source, rname); 96238384Sjkim RangeWrap wtype = new RangeWrap(source, rtype); 97238384Sjkim Wrap wVarDecl = new VarDeclareWrap(wtype, brackets, wname); 98238384Sjkim Wrap wmeth; 99238384Sjkim 100238384Sjkim if (rinit == null) { 101238384Sjkim wmeth = new CompoundWrap(new NoWrap(" "), " return null;\n"); 102238384Sjkim } else { 103238384Sjkim RangeWrap winit = new RangeWrap(source, rinit); 104238384Sjkim // int x = y 105238384Sjkim // int x_ = y; return x = x_; 106238384Sjkim // decl + "_ = " + init ; + "return " + name + "=" + name + "_ ;" 107238384Sjkim wmeth = new CompoundWrap( 108238384Sjkim wtype, brackets + " ", wname, "_ =\n ", winit, semi(winit), 109238384Sjkim " return ", wname, " = ", wname, "_;\n" 110238384Sjkim ); 111238384Sjkim } 112238384Sjkim Wrap wInitMeth = new DoitMethodWrap(wmeth); 113238384Sjkim return new CompoundWrap(wVarDecl, wInitMeth); 114238384Sjkim } 115238384Sjkim 116238384Sjkim public static Wrap tempVarWrap(String source, String typename, String name) { 117238384Sjkim RangeWrap winit = new NoWrap(source); 118238384Sjkim // y 119238384Sjkim // return $1 = y; 120238384Sjkim // "return " + $1 + "=" + init ; 121238384Sjkim Wrap wmeth = new CompoundWrap("return " + name + " =\n ", winit, semi(winit)); 122238384Sjkim Wrap wInitMeth = new DoitMethodWrap(wmeth); 123238384Sjkim 124238384Sjkim String varDecl = " public static\n " + typename + " " + name + ";\n"; 125238384Sjkim return new CompoundWrap(varDecl, wInitMeth); 126238384Sjkim } 127238384Sjkim 128238384Sjkim public static Wrap importWrap(String source) { 129238384Sjkim return new NoWrap(source); 130238384Sjkim } 131238384Sjkim 132238384Sjkim public static Wrap classMemberWrap(String source) { 133238384Sjkim Wrap w = new NoWrap(source); 134238384Sjkim return new CompoundWrap(" public static\n ", w); 135238384Sjkim } 136238384Sjkim 137238384Sjkim private static int countLines(String s) { 138238384Sjkim return countLines(s, 0, s.length()); 139238384Sjkim } 140238384Sjkim 141238384Sjkim private static int countLines(String s, int from, int toEx) { 142238384Sjkim int cnt = 0; 143238384Sjkim int idx = from; 144238384Sjkim while ((idx = s.indexOf('\n', idx)) > 0) { 145238384Sjkim if (idx >= toEx) break; 146238384Sjkim ++cnt; 147238384Sjkim ++idx; 148238384Sjkim } 149238384Sjkim return cnt; 150238384Sjkim } 151238384Sjkim 152238384Sjkim public static final class Range { 153238384Sjkim final int begin; 154238384Sjkim 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} 459