1 28 29 package com.caucho.es.parser; 30 31 import com.caucho.es.*; 32 import com.caucho.java.LineMap; 33 import com.caucho.util.CharBuffer; 34 import com.caucho.util.IntMap; 35 import com.caucho.vfs.Path; 36 import com.caucho.vfs.WriteStream; 37 38 import java.io.IOException ; 39 import java.util.ArrayList ; 40 import java.util.HashMap ; 41 import java.util.Iterator ; 42 43 class ParseClass { 44 private String srcFilename; 45 private LineMap lineMap; 46 47 private Parser parser; 48 49 private String className; 51 private String pkg; 53 private String name; 55 private ESId proto; 56 57 private ParseClass root; 59 60 private HashMap variables = new HashMap (); 62 63 private ArrayList classes = new ArrayList (); 65 66 private ArrayList functions = new ArrayList (); 68 69 private IntMap funMap = new IntMap(); 70 private HashMap names = new HashMap (); 71 private HashMap literals = new HashMap (); 72 private HashMap mangledSet = new HashMap (); 73 private Function global; 74 private int unique; 75 private int callDepth; 76 private ArrayList imports = new ArrayList (); 77 private ArrayList javaImports = new ArrayList (); 78 private WriteStream os; 79 80 private int printDepth; 81 private boolean isFirst; 82 83 private int destLine; 84 private Path sourcePath; 85 86 92 ParseClass(String srcFilename, String name) 93 { 94 this.srcFilename = srcFilename; 95 this.root = this; 96 97 className = name; 98 99 int p = name.lastIndexOf('.'); 100 101 if (p >= 0) { 102 pkg = name.substring(0, p); 103 this.name = name.substring(p + 1); 104 } 105 else { 106 this.name = name; 107 } 108 109 lineMap = new LineMap(name, srcFilename); 110 lineMap.add(1, 1); 111 destLine = 1; 112 } 113 114 117 void setSourcePath(Path sourcePath) 118 { 119 this.sourcePath = sourcePath; 120 } 121 122 125 Path getScriptPath() 126 { 127 return root.parser.getScriptPath(); 128 } 129 130 void setParser(Parser parser) 131 { 132 root.parser = parser; 133 } 134 135 void setWriteStream(WriteStream os) 136 { 137 this.os = os; 138 } 139 140 145 ParseClass newClass(ESId id) 146 { 147 ParseClass cl = new ParseClass(srcFilename, id.toString()); 148 149 classes.add(cl); 150 cl.root = root; 151 152 return cl; 153 } 154 155 Function newFunction(Function oldFun, ESId id, boolean isClass) 156 { 157 if (id == null) 158 id = ESId.intern("$lambda" + unique++); 159 String realId = "_f_" + id.toString(); 160 161 while (names.get(realId) != null) { 162 realId = realId + unique++; 163 } 164 names.put(realId, realId); 165 166 Function fun = new Function(this, oldFun, realId, id, isClass); 167 setFunction(fun); 168 169 return fun; 170 } 171 172 void setFunction(Function function) 173 { 174 int index; 175 if ((index = funMap.get(function.name)) >= 0) { 176 function.num = index; 177 functions.set(index, function); 178 } 179 else { 180 function.num = functions.size(); 181 funMap.put(function.name, functions.size()); 182 functions.add(function); 183 } 184 } 185 186 void addImport(String importName) 187 { 188 if (! imports.contains(importName)) 189 imports.add(importName); 190 } 191 192 195 void addJavaImport(String importName) 196 { 197 if (! javaImports.contains(importName)) 198 javaImports.add(importName); 199 } 200 201 204 Variable getVariable(ESId id) 205 { 206 return (Variable) variables.get(id); 207 } 208 209 212 void addVariable(ESId id, Variable var) 213 { 214 variables.put(id, var); 215 var.setJavaGlobal(true); 216 } 217 218 void setGlobal(Function global) 219 { 220 this.global = global; 221 } 222 223 void setProto(ESId proto) 224 { 225 this.proto = proto; 226 } 227 228 void addFunction(Function function) 229 { 230 setFunction(function); 231 } 232 233 void writeCode(WriteStream os) throws IOException 234 { 235 this.os = os; 236 237 println("/**"); 238 println(" * Generated by " + com.caucho.Version.FULL_VERSION); 239 println(" */"); 240 println(); 241 println("package " + pkg + ";"); 242 println("import java.io.*;"); 243 println("import com.caucho.es.*;"); 244 println("import com.caucho.util.*;"); 245 for (int i = 0; i < javaImports.size(); i++) 246 println("import " + javaImports.get(i) + ";"); 247 248 println("public class " + name + " extends com.caucho.es.Script {"); 249 250 pushDepth(); 251 252 writeExecute(); 253 254 writeClassContents(); 255 256 writeLastModified(); 257 printLineMap(); 258 259 popDepth(); 260 261 println("}"); 262 } 263 264 268 void writeClassContents() throws IOException 269 { 270 if (os == null) 271 os = root.os; 272 273 String name = this == root ? "js_global" : this.name; 274 275 println(); 276 println("public static class " + name + " {"); 277 pushDepth(); 278 println(name + "_es _js;"); 279 280 Iterator iter = variables.values().iterator(); 281 while (iter.hasNext()) { 282 Variable var = (Variable) iter.next(); 283 284 writeVarDecl(var, true); 285 } 286 287 for (int i = 0; i < functions.size(); i++) { 288 Function fun = (Function) functions.get(i); 289 290 println(); 291 fun.writeCode(this); 292 } 293 294 popDepth(); 295 println("}"); 296 297 println(); 298 if (name.equals("js_global")) 299 println("public static class js_global_es extends ESGlobal {"); 300 else 301 println("public static class " + name + "_es extends ESClass {"); 302 pushDepth(); 303 println(name + " _js_object;"); 304 println(); 305 306 println(); 307 if (name.equals("js_global")) { 308 println("js_global_es(Global resin)"); 309 println("{"); 310 println(" super(resin);"); 311 println(" resin.setGlobal(this);"); 312 } 313 else { 314 println(name + "_es()"); 315 println("{"); 316 } 317 println(" _js_object = new " + name + "();"); 318 println(" _js_object._js = this;"); 319 println("}"); 320 321 writeMap(); 322 323 printGetProperty(); 324 printPropNames(); 325 326 writeInit(); 327 writeWrapperInit(name); 328 writeStaticInit(); 329 writeExport(); 330 331 popDepth(); 332 println("}"); 333 334 for (int i = 0; i < classes.size(); i++) { 335 ParseClass subClass = (ParseClass) classes.get(i); 336 337 subClass.setWriteStream(os); 338 subClass.writeClassContents(); 339 } 340 } 341 342 void writeExport() throws IOException 343 { 344 println(); 345 println("public void export(ESObject dst) throws Throwable"); 346 println("{"); 347 348 println(" ESBase tmp;"); 349 350 for (int i = 0; 351 global.functions != null && i < global.functions.size(); 352 i++) { 353 Function fun = (Function) global.functions.get(i); 354 355 println(" tmp = getProperty(\"" + fun.id + "\");"); 356 println(" dst.put(\"" + fun.id + "\", tmp, ESBase.DONT_ENUM);"); 357 } 358 359 for (int i = 0; i < classes.size(); i++) { 360 ParseClass cl = (ParseClass) classes.get(i); 361 362 Function fun = cl.getFunction(ESId.intern(cl.name)); 363 364 println(" tmp = getProperty(\"" + cl.name + "\");"); 365 println(" dst.put(\"" + cl.name + "\", tmp, ESBase.DONT_ENUM);"); 366 } 367 368 println("}"); 369 } 370 371 void writeExecute() 372 throws IOException 373 { 374 println("public ESGlobal initClass(Global resin) throws Throwable"); 375 println("{"); 376 pushDepth(); 377 println("resin.addScript(\"" + className + "\", this);"); 378 379 println("js_global_es test = new js_global_es(resin);"); 380 println("test._init(resin, test);"); 381 println("return test;"); 382 popDepth(); 383 println("}"); 384 } 385 386 void writeWrapperInit(String name) 387 throws IOException 388 { 389 } 390 391 void writeVarDecl(Variable var, boolean init) 392 throws IOException 393 { 394 if (var.getType() == Expr.TYPE_BOOLEAN) { 395 print("boolean " + var.getId()); 396 if (init) 397 println(" = false;"); 398 else 399 println(";"); 400 } 401 else if (var.getType() == Expr.TYPE_INTEGER) { 402 print("int " + var.getId()); 403 if (init) 404 println(" = 0;"); 405 else 406 println(";"); 407 } 408 else if (var.getType() == Expr.TYPE_NUMBER) { 409 print("double " + var.getId()); 410 if (init) 411 println(" = Double.NaN;"); 412 else 413 println(";"); 414 } 415 else if (var.getType() == Expr.TYPE_STRING) { 416 print("ESString " + var.getId()); 417 if (init) 418 println(" = ESString.create(\"\");"); 419 else 420 println(";"); 421 } 422 else if (var.getType() == Expr.TYPE_JAVA && 423 var.getTypeExpr() != null) { 424 TypeExpr type = (TypeExpr) var.getTypeExpr(); 425 426 println(type.getTypeName() + " " + var.getId() + ";"); 427 } 428 else { 429 if (init) 430 println("ESBase " + var.getId() + " = ESBase.esUndefined;"); 431 else 432 println("ESBase " + var.getId() + ";"); 433 } 434 } 435 436 void printId(ESId id) throws IOException 437 { 438 print("js_global_es."); 439 print(getMangledLiteral(id)); 440 } 441 442 String getMangledLiteral(ESBase value) 443 { 444 String literal = (String ) literals.get(value); 445 446 if (literal == null) { 447 literal = mangleLiteral(value); 448 literals.put(value, literal); 449 } 450 451 return literal; 452 } 453 454 void pushCall() 456 { 457 callDepth++; 458 } 459 460 void popCall(int n) 461 { 462 callDepth -= n; 463 } 464 465 int getCallDepth() 466 { 467 return callDepth; 468 } 469 470 void printLiteral(ESBase obj) throws IOException 471 { 472 if (obj == null) 473 print("ESBase.esNull"); 474 else if (obj instanceof ESNull) 475 print("ESBase.esNull"); 476 else if (obj instanceof ESUndefined) 477 print("ESBase.esUndefined"); 478 else if (obj == ESBoolean.TRUE) 479 print("ESBoolean.TRUE"); 480 else if (obj == ESBoolean.FALSE) 481 print("ESBoolean.FALSE"); 482 else { 483 String literal = (String ) literals.get(obj); 484 485 if (literal == null) { 486 try { 487 if (obj instanceof ESNumber && Double.isNaN(obj.toNum())) { 488 print("ESNumber.NaN"); 489 return; 490 } 491 } catch (Throwable e) { 492 } 493 literal = mangleLiteral(obj); 494 literals.put(obj, literal); 495 } 496 497 print("js_global_es."); 498 print(literal); 499 } 500 } 501 502 private String mangleLiteral(Object obj) 503 { 504 String s = obj.toString(); 505 CharBuffer cb = new CharBuffer("_l_"); 506 for (int i = 0; i < s.length() && i < 32; i++) { 507 char ch = s.charAt(i); 508 if (Character.isJavaIdentifierPart(ch) && ch >= ' ' && ch < 127) 510 cb.append(ch); 511 else if (cb.getLastChar() != '_') 512 cb.append("_"); 513 } 514 515 if (mangledSet.get(cb) != null) 516 cb.append("_" + unique++); 517 mangledSet.put(cb, cb); 518 519 return cb.toString(); 520 } 521 522 525 void writeMap() throws IOException 526 { 527 println("public ESBase call(int n, Call call, int length)"); 528 println(" throws Throwable"); 529 println("{"); 530 println(" switch(n) {"); 531 532 for (int i = 0; i < functions.size(); i++) { 533 Function fun = (Function) functions.get(i); 534 535 println(" case " + i + ":"); 536 print(" return "); 537 538 Expr expr = fun.getReturnType(); 539 boolean hasCoerce = false; 540 if (expr == null) { 541 } 542 else if (expr.getType() == Expr.TYPE_INTEGER || 543 expr.getType() == Expr.TYPE_NUMBER) { 544 hasCoerce = true; 545 print("ESNumber.create("); 546 } 547 else if (expr instanceof JavaTypeExpr) { 548 print("call.global.wrap("); 549 } 550 551 print("_js_object."); 552 print(fun.name + "(call, length"); 553 for (int j = 0; j < fun.getFormalSize(); j++) { 554 Variable formal = fun.getFormal(j); 555 556 if (formal.getTypeExpr() instanceof JavaTypeExpr) { 557 TypeExpr type = (TypeExpr) formal.getTypeExpr(); 558 559 print(", (" + type.getTypeName() + ") call.getArgObject(" + j + ", length)"); 560 } 561 else if (formal.getType() == Expr.TYPE_INTEGER) 562 print(", call.getArgInt32(" + j + ", length)"); 563 } 564 print(")"); 565 if (hasCoerce) 566 print(")"); 567 println(";"); 568 } 569 570 println(" default:"); 571 println(" throw new RuntimeException();"); 572 println(" }"); 573 println("}"); 574 } 575 576 void printGetProperty() throws IOException 577 { 578 if (variables.size() == 0) 579 return; 580 581 println(); 582 println("public ESBase getProperty(ESString key) throws Throwable"); 583 println("{"); 584 pushDepth(); 585 println("switch (propNames.get(key)) {"); 586 587 Iterator iter = variables.values().iterator(); 588 int i = 0; 589 while (iter.hasNext()) { 590 Variable var = (Variable) iter.next(); 591 592 println("case " + i + ":"); 593 Class javaClass = var.getTypeExpr().getJavaClass(); 594 if (ESBase.class.isAssignableFrom(javaClass)) 595 println(" return _js_object." + var.getId() + ";"); 596 else 597 println(" return wrap(_js_object." + var.getId() + ");"); 598 599 i++; 600 } 601 602 println("default:"); 603 println(" return super.getProperty(key);"); 604 println("}"); 605 popDepth(); 606 println("}"); 607 } 608 609 void printSetProperty() throws IOException 610 { 611 if (variables.size() == 0) 612 return; 613 614 println(); 615 println("public void setProperty(ESString key, ESBase value) throws Throwable"); 616 println("{"); 617 pushDepth(); 618 println("switch (propNames.get(key)) {"); 619 620 Iterator iter = variables.values().iterator(); 621 int i = 0; 622 while (iter.hasNext()) { 623 Variable var = (Variable) iter.next(); 624 625 println("case " + i + ":"); 626 Class javaClass = var.getTypeExpr().getJavaClass(); 627 if (ESBase.class.isAssignableFrom(javaClass)) 628 println(" _js_object." + var.getId() + " = (" + javaClass.getName() + ") value.toJavaObject();"); 629 else 630 println(" _js_object." + var.getId() + " = value;"); 631 println(" break;"); 632 633 i++; 634 } 635 636 println("default:"); 637 println(" return super.setProperty(key, value);"); 638 println("}"); 639 popDepth(); 640 println("}"); 641 } 642 643 void printPropNames() throws IOException 644 { 645 if (variables.size() == 0) 646 return; 647 648 println(); 649 println("private static com.caucho.util.IntMap propNames;"); 650 println(); 651 println("static {"); 652 pushDepth(); 653 println("propNames = new com.caucho.util.IntMap();"); 654 655 Iterator iter = variables.values().iterator(); 656 int i = 0; 657 while (iter.hasNext()) { 658 Variable var = (Variable) iter.next(); 659 660 println("propNames.put(ESId.intern(\"" + var.getId() + "\"), " + i + ");"); 661 662 i++; 663 } 664 665 popDepth(); 666 println("}"); 667 } 668 669 void writeInit() throws IOException 670 { 671 println(); 672 println("public void _init(Global resin, ESObject global) throws Throwable"); 673 println("{"); 674 675 pushDepth(); 676 677 for (int i = 0; i < imports.size(); i++) { 678 String importName = (String ) imports.get(i); 679 680 print("resin.importScript(this, \""); 681 printString(importName); 682 println("\");"); 683 } 684 685 println("ESClosure fun;"); 686 687 for (int i = 0; global.functions != null && i < global.functions.size(); i++) { 688 Function fun = (Function) global.functions.get(i); 689 690 print("fun = new ESClosure("); 691 print(getMangledLiteral(fun.id)); 692 print(", this, null, " + fun.num + ", "); 693 if (fun.getFormalSize() == 0) 694 print("_a_null"); 695 else 696 print("_a_" + fun.num); 697 println(", global);"); 698 println("global.put(\"" + fun.id + "\", fun, ESBase.DONT_ENUM);"); 699 } 700 701 println("ESObject protoProto;"); 702 println("ESObject proto;"); 703 for (int i = 0; i < classes.size(); i++) { 704 ParseClass cl = (ParseClass) classes.get(i); 705 706 Function fun = cl.getFunction(ESId.intern(cl.name)); 707 708 println("{"); 709 pushDepth(); 710 println(cl.name + "_es jsClass;"); 711 712 println("jsClass = new " + cl.name + "_es();"); 713 if (cl.proto != null) { 714 print("proto = new ESObject(\"Object\", getProperty("); 715 print(getMangledLiteral(cl.proto)); 716 println(").getProperty("); 717 printLiteral(ESId.intern("prototype")); 718 println("));"); 719 } 720 else 721 println("proto = resin.createObject();"); 722 println("jsClass._init(resin, proto);"); 723 print("fun = new ESClosure("); 724 print(getMangledLiteral(ESId.intern(cl.name))); 725 print(", jsClass, proto, " + fun.num + ", "); 726 if (fun.getFormalSize() == 0) 727 print("_a_null"); 728 else 729 print("_a_" + (i + functions.size())); 730 println(", null);"); 731 println("setProperty(\"" + cl.name + "\", fun);"); 732 733 popDepth(); 734 println("}"); 735 } 736 737 popDepth(); 738 println("}"); 739 } 740 741 void writeLastModified() throws IOException 742 { 743 println(); 744 println("public boolean isModified()"); 745 println("{"); 746 if (sourcePath == null || sourcePath.getLastModified() <= 0) 747 println(" return false;"); 748 else if (getScriptPath().lookup(sourcePath.getUserPath()).exists()) { 749 print(" return scriptPath.lookup(\""); 750 printString(sourcePath.getUserPath()); 751 println("\").getLastModified() != " + sourcePath.getLastModified() + "L;"); 752 } 753 else { 754 print(" return com.caucho.vfs.Vfs.lookup(\""); 755 printString(sourcePath.getFullPath()); 756 println("\").getLastModified() != " + sourcePath.getLastModified() + "L;"); 757 } 758 759 println("}"); 760 } 761 762 Function getFunction(ESId name) 763 { 764 for (int i = 0; i < functions.size(); i++) { 765 Function fun = (Function) functions.get(i); 766 if (fun.id == name) 767 return fun; 768 } 769 770 return null; 771 } 772 773 boolean hasFunction(ArrayList functions, ESId var) 774 { 775 for (int i = 2; i < functions.size(); i++) { 776 Function fun = (Function) functions.get(i); 777 if (fun.id == var) 778 return true; 779 } 780 781 return false; 782 } 783 784 void writeStaticInit() throws IOException 785 { 786 Iterator iter = literals.keySet().iterator(); 787 788 if (iter.hasNext()) 789 println(); 790 791 while (iter.hasNext()) { 792 Object o = iter.next(); 793 String name = (String ) literals.get(o); 794 795 if (o instanceof ESId) { 796 print("static ESId " + name); 797 print(" = ESId.intern(\""); 798 printString(String.valueOf(o)); 799 println("\");"); 800 } 801 else if (o instanceof ESString) { 802 print("static ESString " + name); 803 print(" = ESString.create(\""); 804 printString(String.valueOf(o)); 805 println("\");"); 806 } 807 else if (o instanceof ESNumber) { 808 print("static ESNumber " + name); 809 double v = ((ESNumber) o).toNum(); 810 if (Double.isInfinite(v)) 811 println(" = ESNumber.create(Double.POSITIVE_INFINITY);"); 812 else if (Double.isInfinite(-v)) 813 println(" = ESNumber.create(Double.NEGATIVE_INFINITY);"); 814 else if (Double.isNaN(v)) 815 throw new RuntimeException (); 816 else 817 println(" = ESNumber.create(" + o + "D);"); 818 } 819 else 820 throw new RuntimeException (); 821 } 822 823 println("static ESId[] _a_null = new ESId[0];"); 824 for (int i = 0; i < functions.size(); i++) { 825 Function fun = (Function) functions.get(i); 826 827 printFormals(fun, i); 828 } 829 830 for (int i = 0; i < classes.size(); i++) { 831 ParseClass cl = (ParseClass) classes.get(i); 832 833 Function fun = cl.getFunction(ESId.intern(cl.name)); 834 835 printFormals(fun, i + functions.size()); 836 } 837 } 838 839 void setLine(String filename, int line) 840 { 841 lineMap.add(filename, line, destLine); 842 } 843 844 847 void printLineMap() throws IOException 848 { 849 String dst = name + ".java"; 850 String src = srcFilename; 851 String srcTail = srcFilename; 852 853 int p = srcTail.lastIndexOf('/'); 854 if (p >= 0) 855 srcTail = srcTail.substring(p + 1); 856 p = srcTail.lastIndexOf('\\'); 857 if (p >= 0) 858 srcTail = srcTail.substring(p + 1); 859 860 println(); 861 println("public com.caucho.java.LineMap getLineMap()"); 862 println("{"); 863 pushDepth(); 864 print("com.caucho.java.LineMap lineMap = new com.caucho.java.LineMap(\""); 865 printString(dst); 866 print("\", \""); 867 printString(srcTail); 868 println("\");"); 869 println("lineMap.add(1, 1);"); 870 Iterator iter = lineMap.iterator(); 871 while (iter.hasNext()) { 872 LineMap.Line line = (LineMap.Line) iter.next(); 873 874 if (line.getSourceFilename() == src) { 875 println("lineMap.add(" + line.getSourceLine() + ", " + 876 line.getDestinationLine() + ");"); 877 } 878 else { 879 src = line.getSourceFilename(); 880 srcTail = src; 881 p = srcTail.lastIndexOf('/'); 882 if (p >= 0) 883 srcTail = srcTail.substring(p + 1); 884 p = srcTail.lastIndexOf('\\'); 885 if (p >= 0) 886 srcTail = srcTail.substring(p + 1); 887 888 print("lineMap.add(\""); 889 printString(srcTail); 890 println("\", " + 891 line.getSourceLine() + ", " + 892 line.getDestinationLine() + ");"); 893 } 894 } 895 896 println("return lineMap;"); 897 popDepth(); 898 println("}"); 899 } 900 901 private void printFormals(Function fun, int i) 902 throws IOException 903 { 904 if (fun.getFormalSize() > 0) { 905 print(" private static ESId[] _a_" + i + " = new ESId[] {"); 906 for (int j = 0; fun.formals != null && j < fun.formals.size(); j++) { 907 908 if (j != 0) 909 print(","); 910 Variable var = (Variable) fun.formals.get(j); 911 print(" ESId.intern(\"" + var.getId() + "\")"); 912 } 913 println("};"); 914 } 915 } 916 917 920 void printString(String s) throws IOException 921 { 922 for (int i = 0; i < s.length(); i++) { 923 if (i > 0 && i % (16 * 1024) == 0) 924 os.print("\" + \""); 925 926 char ch = s.charAt(i); 927 switch (ch) { 928 case '\\': 929 os.print("\\\\"); 930 break; 931 case '\n': 932 os.print("\\n"); 933 break; 934 case '\r': 935 os.print("\\r"); 936 break; 937 case '\t': 938 os.print("\\t"); 939 break; 940 case '"': 941 os.print("\\\""); 942 break; 943 default: 944 if (ch >= 32 && ch < 127) 945 os.print(ch); 946 else { 947 os.print("\\u"); 948 printHex(ch >> 12); 949 printHex(ch >> 8); 950 printHex(ch >> 4); 951 printHex(ch >> 0); 952 } 953 break; 954 } 955 } 956 } 957 958 void printHex(int i) throws IOException 959 { 960 i &= 0xf; 961 if (i < 10) { 962 os.print(i); 963 } 964 else { 965 os.print((char) ('a' + i - 10)); 966 } 967 } 968 969 void pushDepth() 970 { 971 printDepth += 2; 972 } 973 974 void popDepth() 975 { 976 printDepth -= 2; 977 } 978 979 void print(boolean b) throws IOException 980 { 981 if (isFirst) 982 printSpaces(); 983 root.os.print(b); 984 } 985 986 void print(int i) throws IOException 987 { 988 if (isFirst) 989 printSpaces(); 990 root.os.print(i); 991 } 992 993 void print(char c) throws IOException 994 { 995 if (isFirst) 996 printSpaces(); 997 998 root.os.print(c); 999 if (c == '\n') 1000 destLine++; 1001 } 1002 1003 void print(String s) throws IOException 1004 { 1005 if (isFirst) 1006 printSpaces(); 1007 1008 if (s == null) 1009 s = "null"; 1010 1011 for (int i = 0; i < s.length(); i++) { 1012 if (s.charAt(i) == '\n') { 1013 isFirst = true; 1014 destLine++; 1015 } 1016 else 1017 isFirst = false; 1018 } 1019 1020 root.os.print(s); 1021 } 1022 1023 void print(Object o) throws IOException 1024 { 1025 if (isFirst) 1026 printSpaces(); 1027 1028 print(String.valueOf(o)); 1029 } 1030 1031 void println() throws IOException 1032 { 1033 if (isFirst) 1034 printSpaces(); 1035 1036 root.os.println(); 1037 destLine++; 1038 isFirst = true; 1039 } 1040 1041 void println(String s) throws IOException 1042 { 1043 print(s); 1044 println(); 1045 } 1046 1047 void println(Object o) throws IOException 1048 { 1049 print(String.valueOf(o)); 1050 println(); 1051 } 1052 1053 void printSpaces() throws IOException 1054 { 1055 for (int i = 0; i < printDepth; i++) 1056 root.os.print(' '); 1057 isFirst = false; 1058 } 1059 1060 static class Location { 1061 String filename; 1062 int line; 1063 1064 Location(String filename, int line) 1065 { 1066 this.filename = filename; 1067 this.line = line; 1068 } 1069 } 1070} 1071 | Popular Tags |