1 5 6 package polyglot.util; 7 8 import java.io.OutputStream ; 9 import java.io.OutputStreamWriter ; 10 import java.io.Writer ; 11 import java.io.IOException ; 12 import java.util.Vector ; 13 14 20 public class CodeWriter 21 { 22 28 public CodeWriter(OutputStream o, int width_) { 29 output = new OutputStreamWriter (o); 30 width = width_; 31 current = input = new BlockItem(null, 0); 32 } 33 34 40 public CodeWriter(Writer w, int width_) { 41 output = w; 42 width = width_; 43 current = input = new BlockItem(null, 0); 44 } 45 46 49 public void write(String s) { 50 if (s.length() > 0) 51 current.add(new StringItem(s)); 52 } 53 54 55 public void newline() 56 { 57 newline(0); 58 } 59 60 82 public void begin(int n) { 83 BlockItem b = new BlockItem(current, n); 84 current.add(b); 85 current = b; 86 } 87 88 91 public void end() { 92 current = current.parent; 93 } 96 97 106 public void allowBreak(int n) { 107 current.add(new AllowBreak(n, " ")); 108 } 109 110 121 public void allowBreak(int n, String alt) { 122 current.add(new AllowBreak(n, alt)); 123 } 124 125 133 public void newline(int n) { 134 current.add(new Newline(n)); 135 } 136 137 143 public boolean flush() throws IOException { 144 boolean success = true; 145 try { 146 Item.format(input,0, 0, width, width, true, true); 147 } catch (Overrun o) { success = false; } 148 input.sendOutput(output, 0, 0); 149 output.flush(); 150 input.free(); 151 current = input = new BlockItem(null, 0); 152 return success; 153 } 154 158 public String toString() { 159 return input.toString(); 160 } 161 162 BlockItem input; 163 BlockItem current; 164 165 Writer output; 166 int width; 167 public static final boolean debug = false; 168 public static final boolean precompute = false; 169 170 } 175 176 180 class Overrun extends Exception 181 { 182 int amount; 183 184 private Overrun() { } 185 private static Overrun overrun = new Overrun(); 186 187 static Overrun overrun(int amount) { 189 if (CodeWriter.debug) System.err.println("-- Overrun: " + amount); 190 overrun.amount = amount; 191 return overrun; 192 } 193 } 194 195 199 abstract class Item 200 { 201 Item next; 202 203 protected Item() { next = null; } 204 205 224 225 abstract int formatN(int lmargin, int pos, int rmargin, int fin, 226 boolean can_break, boolean nofail) throws Overrun; 227 234 abstract int sendOutput(Writer o, int lmargin, int pos) 235 throws IOException ; 236 237 238 void free() { 239 if( next != null) { 240 next.free(); 241 next = null; 242 } 243 } 244 245 255 static int format(Item it, int lmargin, int pos, int rmargin, int fin, 256 boolean can_break, boolean nofail) throws Overrun { 257 if (CodeWriter.debug) { 258 System.err.println("Format: " + it + "\n lmargin = " + 259 lmargin + " pos = " + pos + " fin = " + fin + 260 (can_break ? " can break" : " no breaks") + 261 (nofail ? " [nofail]" : "")); 262 } 263 if (!nofail && pos > rmargin) { if (CodeWriter.precompute) { 265 if (CodeWriter.debug) { 266 System.err.println("MinWidth of " + it + " = " + 267 getMinWidth(it)); 268 System.err.println("MinPosWidth of " + it + " = " + 269 getMinPosWidth(it)); 270 System.err.println("MinIndent of " + it + " = " + 271 getMinIndent(it)); 272 } 273 int amount = pos + getMinPosWidth(it) - rmargin; 274 int amount1 = lmargin + getMinWidth(it) - rmargin; 275 if (amount1 > amount) amount = amount1; 276 int amount2 = lmargin + getMinIndent(it) - fin; 277 if (amount2 > amount) amount = amount2; 278 throw Overrun.overrun(amount); 279 } else { 280 throw Overrun.overrun(pos - rmargin); 281 } 282 } 283 if (it == null) { if (!nofail && pos > fin) throw Overrun.overrun(pos - fin); 285 return pos; 286 } 287 return it.formatN(lmargin, pos, rmargin, fin, can_break, nofail); 288 } 289 290 309 310 313 314 int min_width = -1; 315 316 317 int min_indent = -1; 318 319 320 int min_pos_width = -1; 321 322 323 boolean contains_brks; 324 boolean cb_init = false; 325 326 static int max(int i, int j) { 327 if (i > j) return i; 328 return j; 329 } 330 331 static int getMinWidth(Item it) { 332 if (it == null) return 0; 333 if (it.min_width >= 0) return it.min_width; 334 int p1 = it.selfMinWidth(); 335 int p2 = it.selfMinIndent(); 336 int p3 = getMinPosWidth(it.next) + p2; 337 int p4 = getMinWidth(it.next); 338 return (it.min_width = max(max(p1, p3), p4)); 339 } 340 341 static int getMinPosWidth(Item it) { 342 if (it == null) return 0; 343 if (it.min_pos_width >= 0) return it.min_pos_width; 344 int p1 = it.selfMinPosWidth(); 345 if (it.next == null || 346 it.selfContainsBreaks()) return p1; 347 return p1 + getMinPosWidth(it.next); 348 } 349 350 static int getMinIndent(Item it) { 351 if (it == null) return 0; 352 if (it.min_indent >= 0) return it.min_indent; 353 int p1 = it.selfMinIndent(); 354 if (it.next == null) return p1; 355 if (containsBreaks(it.next)) 356 return getMinIndent(it.next); 357 return p1 + getMinPosWidth(it.next); 358 } 359 360 static boolean containsBreaks(Item it) { 361 if (it == null) return false; 362 if (it.cb_init) return it.contains_brks; 363 if (it.selfContainsBreaks()) { 364 it.contains_brks = true; 365 it.cb_init = true; 366 return true; 367 } 368 if (it.next == null) return false; 369 it.contains_brks = containsBreaks(it.next); 370 it.cb_init = true; 371 return it.contains_brks; 372 } 373 374 public String summarize(String s) { 375 if (s.length() <= 60) return s; 376 return s.substring(0, 57) + "..."; 377 } 378 379 public String toString() { 380 if (next == null) return summarize(selfToString()); 381 return summarize(selfToString() + next.toString()); 382 } 383 384 abstract String selfToString(); 385 abstract int selfMinIndent(); 386 abstract int selfMinWidth(); 387 abstract int selfMinPosWidth(); 388 abstract boolean selfContainsBreaks(); 389 } 390 391 395 class BlockItem extends Item { 396 BlockItem parent; 397 Item first; 398 Item last; 399 int indent; 400 401 403 BlockItem(BlockItem parent_, int indent_) { 404 parent = parent_; 405 first = last = null; 406 indent = indent_; 407 } 408 409 414 void add(Item it) { 415 if (first == null) { 416 first = it; 417 } else { 418 if (it instanceof StringItem && last instanceof StringItem) { 419 StringItem lasts = (StringItem)last; 420 lasts.appendString(((StringItem)it).s); 421 return; 422 } else { 423 last.next = it; 424 } 425 } 426 last = it; 427 } 428 429 int formatN(int lmargin, int pos, int rmargin, int fin, boolean can_break, 430 boolean nofail) throws Overrun { 431 if (CodeWriter.debug) 432 System.err.println("BlockItem format " + this + "\n lmargin = " + 433 lmargin + " pos = " + pos + " fin = " + fin + 434 (can_break ? " can break" : " no breaks") + 435 (nofail ? " [nofail]" : "")); 436 int this_fin = rmargin - getMinPosWidth(next); 440 boolean this_nofail = false; 443 boolean this_break = false; 446 while (true) { 447 int next_pos; 448 try { 449 next_pos = format(first, pos + indent, pos, rmargin, 450 this_fin, this_break, this_nofail && this_break); 451 } catch (Overrun o) { 452 if (!can_break) throw o; 453 if (!this_break) { this_break = true; continue; } 454 if (this_nofail) throw new Error ("Failed with this_nofail"); 455 if (nofail) { this_nofail = true; continue; } 456 throw o; 457 } 458 try { 459 return format(next, lmargin, next_pos, rmargin, fin, 460 can_break, nofail); 461 } catch (Overrun o) { 462 if (!can_break) throw o; if (next instanceof AllowBreak) throw o; this_break = true; 465 if (nofail) throw new Error ("Failed with nofail"); 466 if (next_pos > this_fin) next_pos = this_fin; 467 this_fin = next_pos - o.amount; 468 if (CodeWriter.debug) 469 System.err.println(" Trying block again with fin = " + 470 this_fin); 471 } 472 } 473 } 474 475 int sendOutput(Writer o, int lmargin, int pos) throws IOException { 476 Item it = first; 477 lmargin = pos+indent; 478 while (it != null) { 479 pos = it.sendOutput(o, lmargin, pos); 480 it = it.next; 481 } 482 return pos; 483 } 484 485 void free() { 486 super.free(); 487 488 parent = null; 489 if( first != null) { 490 first.free(); 491 } 492 last = null; 493 } 494 495 int selfMinWidth() { 496 return getMinWidth(first); 497 } 498 499 int selfMinPosWidth() { 500 return getMinPosWidth(first); 501 } 502 503 int selfMinIndent() { 504 return getMinIndent(first); 505 } 506 507 boolean self_contains_brks; 508 boolean self_contains_brks_init = false; 509 510 boolean selfContainsBreaks() { 511 if (self_contains_brks_init) { 512 return self_contains_brks; 513 } else { 514 return (self_contains_brks = containsBreaks(first)); 515 } 516 } 517 String selfToString() { 518 if (indent == 0) return "[" + first + "]"; 519 else return "[" + indent + first + "]"; 520 } 521 } 522 523 class StringItem extends Item { 524 String s; 525 527 StringItem(String s_) { s = s_; } 529 530 int formatN(int lmargin, int pos, int rmargin, int fin, boolean can_break, 531 boolean nofail) throws Overrun { 532 return format(next, lmargin, pos + s.length(), rmargin, fin, 533 can_break, nofail); 534 } 535 int sendOutput(Writer o, int lm, int pos) throws IOException { 536 o.write(s); 537 return pos + s.length(); 538 } 539 void appendString(String s) { this.s = this.s + s; } 540 boolean selfContainsBreaks() { return false; } 541 int selfMinIndent() { return s.length(); } 542 int selfMinWidth() { return s.length(); } 543 int selfMinPosWidth() { return s.length(); } 544 String selfToString() { 545 java.io.StringWriter sw = new java.io.StringWriter (); 546 for (int i = 0; i < s.length(); i++) { 547 char c = s.charAt(i); 548 if (c == ' ') sw.write("\\ "); 549 else sw.write(c); 550 } 551 return sw.toString(); 552 } 553 } 554 555 class AllowBreak extends Item 556 { 557 int indent; 558 boolean broken = true; 559 String alt; 560 561 564 AllowBreak(int n_, String alt_) { indent = n_; alt = alt_; } 567 568 int formatN(int lmargin, int pos, int rmargin, int fin, boolean can_break, 569 boolean nofail) throws Overrun { 570 if (can_break) { pos = lmargin + indent; broken = true; } 571 else { pos += alt.length(); broken = false; } 572 return format(next, lmargin, pos, rmargin, fin, can_break, nofail); 573 } 574 575 int sendOutput(Writer o, int lmargin, int pos) 576 throws IOException { 577 if (broken) { 578 o.write("\r\n"); 579 for (int i = 0; i < lmargin + indent; i++) o.write(" "); 580 return lmargin + indent; 581 } else { 582 o.write(alt); 583 return pos + alt.length(); 584 } 585 } 586 int selfMinIndent() { return indent; } 587 int selfMinPosWidth() { return 0; } 588 int selfMinWidth() { return indent; } 589 boolean selfContainsBreaks() { return true; } 590 591 String selfToString() { 592 if (indent == 0) return " "; 593 else return "^" + indent; } 594 } 595 596 class Newline extends AllowBreak 597 { 598 Newline(int n_) { super(n_, ""); } 600 601 int formatN(int lmargin, int pos, int rmargin, int fin, boolean can_break, 602 boolean nofail) throws Overrun { 603 broken = true; 604 if (!can_break) throw Overrun.overrun(1); 605 return format(next, lmargin, lmargin + indent, rmargin, fin, 606 can_break, nofail); 607 } 608 609 int sendOutput(Writer o, int lmargin, int pos) 610 throws IOException { 611 o.write("\r\n"); 612 for (int i = 0; i < lmargin + indent; i++) o.write(" "); 613 return lmargin + indent; 614 } 615 } 616 | Popular Tags |