1 16 package com.google.gwt.dev.js; 17 18 import com.google.gwt.dev.js.ast.HasName; 19 import com.google.gwt.dev.js.ast.JsArrayAccess; 20 import com.google.gwt.dev.js.ast.JsArrayLiteral; 21 import com.google.gwt.dev.js.ast.JsBinaryOperation; 22 import com.google.gwt.dev.js.ast.JsBinaryOperator; 23 import com.google.gwt.dev.js.ast.JsBlock; 24 import com.google.gwt.dev.js.ast.JsBooleanLiteral; 25 import com.google.gwt.dev.js.ast.JsBreak; 26 import com.google.gwt.dev.js.ast.JsCase; 27 import com.google.gwt.dev.js.ast.JsCatch; 28 import com.google.gwt.dev.js.ast.JsConditional; 29 import com.google.gwt.dev.js.ast.JsContext; 30 import com.google.gwt.dev.js.ast.JsContinue; 31 import com.google.gwt.dev.js.ast.JsDebugger; 32 import com.google.gwt.dev.js.ast.JsDecimalLiteral; 33 import com.google.gwt.dev.js.ast.JsDefault; 34 import com.google.gwt.dev.js.ast.JsDoWhile; 35 import com.google.gwt.dev.js.ast.JsEmpty; 36 import com.google.gwt.dev.js.ast.JsExprStmt; 37 import com.google.gwt.dev.js.ast.JsExpression; 38 import com.google.gwt.dev.js.ast.JsFor; 39 import com.google.gwt.dev.js.ast.JsForIn; 40 import com.google.gwt.dev.js.ast.JsFunction; 41 import com.google.gwt.dev.js.ast.JsIf; 42 import com.google.gwt.dev.js.ast.JsIntegralLiteral; 43 import com.google.gwt.dev.js.ast.JsInvocation; 44 import com.google.gwt.dev.js.ast.JsLabel; 45 import com.google.gwt.dev.js.ast.JsName; 46 import com.google.gwt.dev.js.ast.JsNameRef; 47 import com.google.gwt.dev.js.ast.JsNew; 48 import com.google.gwt.dev.js.ast.JsNullLiteral; 49 import com.google.gwt.dev.js.ast.JsObjectLiteral; 50 import com.google.gwt.dev.js.ast.JsParameter; 51 import com.google.gwt.dev.js.ast.JsPostfixOperation; 52 import com.google.gwt.dev.js.ast.JsPrefixOperation; 53 import com.google.gwt.dev.js.ast.JsProgram; 54 import com.google.gwt.dev.js.ast.JsPropertyInitializer; 55 import com.google.gwt.dev.js.ast.JsRegExp; 56 import com.google.gwt.dev.js.ast.JsReturn; 57 import com.google.gwt.dev.js.ast.JsStatement; 58 import com.google.gwt.dev.js.ast.JsStringLiteral; 59 import com.google.gwt.dev.js.ast.JsSwitch; 60 import com.google.gwt.dev.js.ast.JsThisRef; 61 import com.google.gwt.dev.js.ast.JsThrow; 62 import com.google.gwt.dev.js.ast.JsTry; 63 import com.google.gwt.dev.js.ast.JsUnaryOperator; 64 import com.google.gwt.dev.js.ast.JsVars; 65 import com.google.gwt.dev.js.ast.JsVisitor; 66 import com.google.gwt.dev.js.ast.JsWhile; 67 import com.google.gwt.dev.js.ast.JsVars.JsVar; 68 import com.google.gwt.dev.util.TextOutput; 69 70 import java.util.Iterator ; 71 72 75 public class JsToStringGenerationVisitor extends JsVisitor { 76 77 private static final char[] CHARS_BREAK = "break".toCharArray(); 78 private static final char[] CHARS_CASE = "case".toCharArray(); 79 private static final char[] CHARS_CATCH = "catch".toCharArray(); 80 private static final char[] CHARS_CONTINUE = "continue".toCharArray(); 81 private static final char[] CHARS_DEBUGGER = "debugger".toCharArray(); 82 private static final char[] CHARS_DEFAULT = "default".toCharArray(); 83 private static final char[] CHARS_DELETE = "delete".toCharArray(); 84 private static final char[] CHARS_DO = "do".toCharArray(); 85 private static final char[] CHARS_ELSE = "else".toCharArray(); 86 private static final char[] CHARS_FALSE = "false".toCharArray(); 87 private static final char[] CHARS_FINALLY = "finally".toCharArray(); 88 private static final char[] CHARS_FOR = "for".toCharArray(); 89 private static final char[] CHARS_FUNCTION = "function".toCharArray(); 90 private static final char[] CHARS_IF = "if".toCharArray(); 91 private static final char[] CHARS_IN = "in".toCharArray(); 92 private static final char[] CHARS_NEW = "new".toCharArray(); 93 private static final char[] CHARS_NULL = "null".toCharArray(); 94 private static final char[] CHARS_RETURN = "return".toCharArray(); 95 private static final char[] CHARS_SWITCH = "switch".toCharArray(); 96 private static final char[] CHARS_THIS = "this".toCharArray(); 97 private static final char[] CHARS_THROW = "throw".toCharArray(); 98 private static final char[] CHARS_TRUE = "true".toCharArray(); 99 private static final char[] CHARS_TRY = "try".toCharArray(); 100 private static final char[] CHARS_VAR = "var".toCharArray(); 101 private static final char[] CHARS_WHILE = "while".toCharArray(); 102 private static final char[] HEX_DIGITS = { 103 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 104 'E', 'F'}; 105 106 109 private static final int JSBLOCK_LINES_TO_PRINT = 3; 110 111 protected boolean needSemi = true; 112 private final TextOutput p; 113 114 public JsToStringGenerationVisitor(TextOutput out) { 115 this.p = out; 116 } 117 118 public boolean visit(JsArrayAccess x, JsContext ctx) { 119 JsExpression arrayExpr = x.getArrayExpr(); 120 _parenPush(x, arrayExpr, false); 121 accept(arrayExpr); 122 _parenPop(x, arrayExpr, false); 123 _lsquare(); 124 accept(x.getIndexExpr()); 125 _rsquare(); 126 return false; 127 } 128 129 public boolean visit(JsArrayLiteral x, JsContext ctx) { 130 _lsquare(); 131 boolean sep = false; 132 for (Iterator iter = x.getExpressions().iterator(); iter.hasNext();) { 133 JsExpression arg = (JsExpression) iter.next(); 134 sep = _sepCommaOptSpace(sep); 135 _parenPushIfCommaExpr(arg); 136 accept(arg); 137 _parenPopIfCommaExpr(arg); 138 } 139 _rsquare(); 140 return false; 141 } 142 143 public boolean visit(JsBinaryOperation x, JsContext ctx) { 144 JsBinaryOperator op = x.getOperator(); 145 JsExpression arg1 = x.getArg1(); 146 _parenPush(x, arg1, !op.isLeftAssociative()); 147 accept(arg1); 148 boolean needSpace = op.isKeyword() || arg1 instanceof JsPostfixOperation; 149 if (needSpace) { 150 _parenPopOrSpace(x, arg1, !op.isLeftAssociative()); 151 } else { 152 _parenPop(x, arg1, !op.isLeftAssociative()); 153 _spaceOpt(); 154 } 155 p.print(op.getSymbol()); 156 JsExpression arg2 = x.getArg2(); 157 needSpace = op.isKeyword() || arg2 instanceof JsPrefixOperation; 158 if (needSpace) { 159 _parenPushOrSpace(x, arg2, op.isLeftAssociative()); 160 } else { 161 _spaceOpt(); 162 _parenPush(x, arg2, op.isLeftAssociative()); 163 } 164 accept(arg2); 165 _parenPop(x, arg2, op.isLeftAssociative()); 166 return false; 167 } 168 169 public boolean visit(JsBlock x, JsContext ctx) { 170 printJsBlockOptionalTruncate(x, true); 171 return false; 172 } 173 174 public boolean visit(JsBooleanLiteral x, JsContext ctx) { 175 if (x.getValue()) { 176 _true(); 177 } else { 178 _false(); 179 } 180 return false; 181 } 182 183 public boolean visit(JsBreak x, JsContext ctx) { 184 _break(); 185 186 JsNameRef label = x.getLabel(); 187 if (label != null) { 188 _space(); 189 _nameRef(label); 190 } 191 192 return false; 193 } 194 195 public boolean visit(JsCase x, JsContext ctx) { 196 _case(); 197 _space(); 198 accept(x.getCaseExpr()); 199 _colon(); 200 _newlineOpt(); 201 202 indent(); 203 for (Iterator iter = x.getStmts().iterator(); iter.hasNext();) { 204 JsStatement stmt = (JsStatement) iter.next(); 205 needSemi = true; 206 accept(stmt); 207 if (needSemi) { 208 _semi(); 209 } 210 _newlineOpt(); 211 } 212 outdent(); 213 needSemi = false; 214 return false; 215 } 216 217 public boolean visit(JsCatch x, JsContext ctx) { 218 _spaceOpt(); 219 _catch(); 220 _spaceOpt(); 221 _lparen(); 222 _nameDef(x.getParameter().getName()); 223 224 JsExpression catchCond = x.getCondition(); 227 if (catchCond != null) { 228 _space(); 229 _if(); 230 _space(); 231 accept(catchCond); 232 } 233 234 _rparen(); 235 _spaceOpt(); 236 accept(x.getBody()); 237 238 return false; 239 } 240 241 public boolean visit(JsConditional x, JsContext ctx) { 242 { 244 JsExpression testExpression = x.getTestExpression(); 245 _parenPush(x, testExpression, true); 246 accept(testExpression); 247 _parenPop(x, testExpression, true); 248 } 249 _questionMark(); 250 { 251 JsExpression thenExpression = x.getThenExpression(); 252 _parenPush(x, thenExpression, true); 253 accept(thenExpression); 254 _parenPop(x, thenExpression, true); 255 } 256 _colon(); 257 { 258 JsExpression elseExpression = x.getElseExpression(); 259 _parenPush(x, elseExpression, false); 260 accept(elseExpression); 261 _parenPop(x, elseExpression, false); 262 } 263 return false; 264 } 265 266 public boolean visit(JsContinue x, JsContext ctx) { 267 _continue(); 268 269 JsNameRef label = x.getLabel(); 270 if (label != null) { 271 _space(); 272 _nameRef(label); 273 } 274 275 return false; 276 } 277 278 public boolean visit(JsDebugger x, JsContext ctx) { 279 _debugger(); 280 return false; 281 } 282 283 public boolean visit(JsDecimalLiteral x, JsContext ctx) { 284 String s = x.getValue(); 285 if (s.startsWith("-")) { 287 _space(); 288 } 289 p.print(s); 290 return false; 291 } 292 293 public boolean visit(JsDefault x, JsContext ctx) { 294 _default(); 295 _colon(); 296 297 indent(); 298 for (Iterator iter = x.getStmts().iterator(); iter.hasNext();) { 299 JsStatement stmt = (JsStatement) iter.next(); 300 needSemi = true; 301 accept(stmt); 302 if (needSemi) { 303 _semi(); 304 } 305 _newlineOpt(); 306 } 307 outdent(); 308 needSemi = false; 309 return false; 310 } 311 312 public boolean visit(JsDoWhile x, JsContext ctx) { 313 _do(); 314 _nestedPush(x.getBody(), true); 315 accept(x.getBody()); 316 _nestedPop(x.getBody()); 317 if (needSemi) { 318 _semi(); 319 _newlineOpt(); 320 } else { 321 _spaceOpt(); 322 needSemi = true; 323 } 324 _while(); 325 _spaceOpt(); 326 _lparen(); 327 accept(x.getCondition()); 328 _rparen(); 329 return false; 330 } 331 332 public boolean visit(JsEmpty x, JsContext ctx) { 333 return false; 334 } 335 336 public boolean visit(JsExprStmt x, JsContext ctx) { 337 final JsExpression expr = x.getExpression(); 338 accept(expr); 339 return false; 340 } 341 342 public boolean visit(JsFor x, JsContext ctx) { 343 _for(); 344 _spaceOpt(); 345 _lparen(); 346 347 if (x.getInitExpr() != null) { 350 accept(x.getInitExpr()); 351 } else if (x.getInitVars() != null) { 352 accept(x.getInitVars()); 353 } 354 355 _semi(); 356 357 if (x.getCondition() != null) { 360 _spaceOpt(); 361 accept(x.getCondition()); 362 } 363 364 _semi(); 365 366 if (x.getIncrExpr() != null) { 369 _spaceOpt(); 370 accept(x.getIncrExpr()); 371 } 372 373 _rparen(); 374 _nestedPush(x.getBody(), false); 375 accept(x.getBody()); 376 _nestedPop(x.getBody()); 377 return false; 378 } 379 380 public boolean visit(JsForIn x, JsContext ctx) { 381 _for(); 382 _spaceOpt(); 383 _lparen(); 384 385 if (x.getIterVarName() != null) { 386 _var(); 387 _space(); 388 _nameDef(x.getIterVarName()); 389 390 if (x.getIterExpr() != null) { 391 _spaceOpt(); 392 _assignment(); 393 _spaceOpt(); 394 accept(x.getIterExpr()); 395 } 396 } else { 397 accept(x.getIterExpr()); 400 } 401 402 _space(); 403 _in(); 404 _space(); 405 accept(x.getObjExpr()); 406 407 _rparen(); 408 _nestedPush(x.getBody(), false); 409 accept(x.getBody()); 410 _nestedPop(x.getBody()); 411 return false; 412 } 413 414 public boolean visit(JsFunction x, JsContext ctx) { 419 _function(); 420 421 if (x.getName() != null) { 424 _space(); 425 _nameOf(x); 426 } 427 428 _lparen(); 429 boolean sep = false; 430 for (Iterator iter = x.getParameters().iterator(); iter.hasNext();) { 431 JsParameter param = (JsParameter) iter.next(); 432 sep = _sepCommaOptSpace(sep); 433 accept(param); 434 } 435 _rparen(); 436 437 accept(x.getBody()); 438 needSemi = true; 439 return false; 440 } 441 442 public boolean visit(JsIf x, JsContext ctx) { 443 _if(); 444 _spaceOpt(); 445 _lparen(); 446 accept(x.getIfExpr()); 447 _rparen(); 448 JsStatement thenStmt = x.getThenStmt(); 449 _nestedPush(thenStmt, false); 450 accept(thenStmt); 451 _nestedPop(thenStmt); 452 JsStatement elseStmt = x.getElseStmt(); 453 if (elseStmt != null) { 454 if (needSemi) { 455 _semi(); 456 _newlineOpt(); 457 } else { 458 _spaceOpt(); 459 needSemi = true; 460 } 461 _else(); 462 boolean elseIf = elseStmt instanceof JsIf; 463 if (!elseIf) { 464 _nestedPush(elseStmt, true); 465 } else { 466 _space(); 467 } 468 accept(elseStmt); 469 if (!elseIf) { 470 _nestedPop(elseStmt); 471 } 472 } 473 return false; 474 } 475 476 public boolean visit(JsIntegralLiteral x, JsContext ctx) { 477 String s = x.getValue().toString(); 478 boolean needParens = s.startsWith("-"); 479 if (needParens) { 480 _lparen(); 481 } 482 p.print(s); 483 if (needParens) { 484 _rparen(); 485 } 486 return false; 487 } 488 489 public boolean visit(JsInvocation x, JsContext ctx) { 490 accept(x.getQualifier()); 491 492 _lparen(); 493 boolean sep = false; 494 for (Iterator iter = x.getArguments().iterator(); iter.hasNext();) { 495 JsExpression arg = (JsExpression) iter.next(); 496 sep = _sepCommaOptSpace(sep); 497 _parenPushIfCommaExpr(arg); 498 accept(arg); 499 _parenPopIfCommaExpr(arg); 500 } 501 _rparen(); 502 return false; 503 } 504 505 public boolean visit(JsLabel x, JsContext ctx) { 506 _nameOf(x); 507 _colon(); 508 _spaceOpt(); 509 accept(x.getStmt()); 510 return false; 511 } 512 513 public boolean visit(JsNameRef x, JsContext ctx) { 514 JsExpression q = x.getQualifier(); 515 if (q != null) { 516 _parenPush(x, q, false); 517 accept(q); 518 _parenPop(x, q, false); 519 _dot(); 520 } 521 _nameRef(x); 522 return false; 523 } 524 525 public boolean visit(JsNew x, JsContext ctx) { 526 _new(); 527 _space(); 528 529 JsExpression ctorExpr = x.getConstructorExpression(); 530 _parenPush(x, ctorExpr, true); 531 accept(ctorExpr); 532 _parenPop(x, ctorExpr, true); 533 534 _lparen(); 535 boolean sep = false; 536 for (Iterator iter = x.getArguments().iterator(); iter.hasNext();) { 537 JsExpression arg = (JsExpression) iter.next(); 538 sep = _sepCommaOptSpace(sep); 539 _parenPushIfCommaExpr(arg); 540 accept(arg); 541 _parenPopIfCommaExpr(arg); 542 } 543 _rparen(); 544 545 return false; 546 } 547 548 public boolean visit(JsNullLiteral x, JsContext ctx) { 549 _null(); 550 return false; 551 } 552 553 public boolean visit(JsObjectLiteral x, JsContext ctx) { 554 _lbrace(); 555 boolean sep = false; 556 for (Iterator iter = x.getPropertyInitializers().iterator(); iter.hasNext();) { 557 sep = _sepCommaOptSpace(sep); 558 JsPropertyInitializer propInit = (JsPropertyInitializer) iter.next(); 559 JsExpression labelExpr = propInit.getLabelExpr(); 560 _parenPushIfConditional(labelExpr); 561 accept(labelExpr); 562 _parenPopIfConditional(labelExpr); 563 _colon(); 564 JsExpression valueExpr = propInit.getValueExpr(); 565 _parenPushIfConditional(valueExpr); 566 accept(valueExpr); 567 _parenPopIfConditional(valueExpr); 568 } 569 _rbrace(); 570 return false; 571 } 572 573 public boolean visit(JsParameter x, JsContext ctx) { 574 _nameOf(x); 575 return false; 576 } 577 578 public boolean visit(JsPostfixOperation x, JsContext ctx) { 579 JsUnaryOperator op = x.getOperator(); 580 JsExpression arg = x.getArg(); 581 _parenPush(x, arg, true); 583 accept(arg); 584 _parenPop(x, arg, true); 585 p.print(op.getSymbol()); 586 return false; 587 } 588 589 public boolean visit(JsPrefixOperation x, JsContext ctx) { 590 JsUnaryOperator op = x.getOperator(); 591 p.print(op.getSymbol()); 592 if (op.isKeyword()) { 593 _space(); 594 } 595 JsExpression arg = x.getArg(); 596 _parenPush(x, arg, true); 598 accept(arg); 599 _parenPop(x, arg, true); 600 return false; 601 } 602 603 public boolean visit(JsProgram x, JsContext ctx) { 604 p.print("<JsProgram>"); 605 return false; 606 } 607 608 public boolean visit(JsPropertyInitializer x, JsContext ctx) { 609 return false; 613 } 614 615 public boolean visit(JsRegExp x, JsContext ctx) { 616 _slash(); 617 p.print(x.getPattern()); 618 _slash(); 619 String flags = x.getFlags(); 620 if (flags != null) { 621 p.print(flags); 622 } 623 return false; 624 } 625 626 public boolean visit(JsReturn x, JsContext ctx) { 627 _return(); 628 JsExpression expr = x.getExpr(); 629 if (expr != null) { 630 _space(); 631 accept(expr); 632 } 633 return false; 634 } 635 636 public boolean visit(JsStringLiteral x, JsContext ctx) { 637 printStringLiteral(x.getValue()); 638 return false; 639 } 640 641 public boolean visit(JsSwitch x, JsContext ctx) { 642 _switch(); 643 _spaceOpt(); 644 _lparen(); 645 accept(x.getExpr()); 646 _rparen(); 647 _spaceOpt(); 648 _blockOpen(); 649 accept(x.getCases()); 650 _blockClose(); 651 return false; 652 } 653 654 public boolean visit(JsThisRef x, JsContext ctx) { 655 _this(); 656 return false; 657 } 658 659 public boolean visit(JsThrow x, JsContext ctx) { 660 _throw(); 661 _space(); 662 accept(x.getExpr()); 663 return false; 664 } 665 666 public boolean visit(JsTry x, JsContext ctx) { 667 _try(); 668 _spaceOpt(); 669 accept(x.getTryBlock()); 670 671 accept(x.getCatches()); 672 673 JsBlock finallyBlock = x.getFinallyBlock(); 674 if (finallyBlock != null) { 675 _spaceOpt(); 676 _finally(); 677 _spaceOpt(); 678 accept(finallyBlock); 679 } 680 681 return false; 682 } 683 684 public boolean visit(JsVar x, JsContext ctx) { 685 _nameOf(x); 686 JsExpression initExpr = x.getInitExpr(); 687 if (initExpr != null) { 688 _spaceOpt(); 689 _assignment(); 690 _spaceOpt(); 691 _parenPushIfCommaExpr(initExpr); 692 accept(initExpr); 693 _parenPopIfCommaExpr(initExpr); 694 } 695 return false; 696 } 697 698 public boolean visit(JsVars x, JsContext ctx) { 699 _var(); 700 _space(); 701 boolean sep = false; 702 for (Iterator iter = x.iterator(); iter.hasNext();) { 703 sep = _sepCommaOptSpace(sep); 704 JsVars.JsVar var = (JsVars.JsVar) iter.next(); 705 accept(var); 706 } 707 return false; 708 } 709 710 public boolean visit(JsWhile x, JsContext ctx) { 711 _while(); 712 _spaceOpt(); 713 _lparen(); 714 accept(x.getCondition()); 715 _rparen(); 716 _nestedPush(x.getBody(), false); 717 accept(x.getBody()); 718 _nestedPop(x.getBody()); 719 return false; 720 } 721 722 protected void _newline() { 724 p.newline(); 725 } 726 727 protected void _newlineOpt() { 728 p.newlineOpt(); 729 } 730 731 protected void printJsBlockOptionalTruncate(JsBlock x, boolean truncate) { 732 boolean needBraces = !x.isGlobalBlock(); 733 734 if (needBraces) { 735 _blockOpen(); 738 } 739 740 int count = 0; 741 for (Iterator iter = x.getStatements().iterator(); iter.hasNext(); ++count) { 742 if (truncate && count > JSBLOCK_LINES_TO_PRINT) { 743 p.print("[...]"); 744 _newlineOpt(); 745 break; 746 } 747 JsStatement stmt = (JsStatement) iter.next(); 748 needSemi = true; 749 accept(stmt); 750 if (needSemi) { 751 758 if (stmt instanceof JsExprStmt 759 && ((JsExprStmt) stmt).getExpression() instanceof JsFunction) { 760 _newline(); 761 } else { 762 _semi(); 763 _newlineOpt(); 764 } 765 } 766 } 767 768 if (needBraces) { 769 _blockClose(); 772 } 773 needSemi = false; 774 } 775 776 private void _assignment() { 777 p.print('='); 778 } 779 780 private void _blockClose() { 781 p.indentOut(); 782 p.print('}'); 783 _newlineOpt(); 784 } 785 786 private void _blockOpen() { 787 p.print('{'); 788 p.indentIn(); 789 _newlineOpt(); 790 } 791 792 private void _break() { 793 p.print(CHARS_BREAK); 794 } 795 796 private void _case() { 797 p.print(CHARS_CASE); 798 } 799 800 private void _catch() { 801 p.print(CHARS_CATCH); 802 } 803 804 private void _colon() { 805 p.print(':'); 806 } 807 808 private void _continue() { 809 p.print(CHARS_CONTINUE); 810 } 811 812 private void _debugger() { 813 p.print(CHARS_DEBUGGER); 814 } 815 816 private void _default() { 817 p.print(CHARS_DEFAULT); 818 } 819 820 private void _delete() { 821 p.print(CHARS_DELETE); 822 } 823 824 private void _do() { 825 p.print(CHARS_DO); 826 } 827 828 private void _dot() { 829 p.print('.'); 830 } 831 832 private void _else() { 833 p.print(CHARS_ELSE); 834 } 835 836 private void _false() { 837 p.print(CHARS_FALSE); 838 } 839 840 private void _finally() { 841 p.print(CHARS_FINALLY); 842 } 843 844 private void _for() { 845 p.print(CHARS_FOR); 846 } 847 848 private void _function() { 849 p.print(CHARS_FUNCTION); 850 } 851 852 private void _if() { 853 p.print(CHARS_IF); 854 } 855 856 private void _in() { 857 p.print(CHARS_IN); 858 } 859 860 private void _lbrace() { 861 p.print('{'); 862 } 863 864 private void _lparen() { 865 p.print('('); 866 } 867 868 private void _lsquare() { 869 p.print('['); 870 } 871 872 private void _nameDef(JsName name) { 873 p.print(name.getShortIdent()); 874 } 875 876 private void _nameOf(HasName hasName) { 877 _nameDef(hasName.getName()); 878 } 879 880 private void _nameRef(JsNameRef nameRef) { 881 p.print(nameRef.getShortIdent()); 882 } 883 884 private boolean _nestedPop(JsStatement statement) { 885 boolean pop = !(statement instanceof JsBlock); 886 if (pop) { 887 p.indentOut(); 888 } 889 return pop; 890 } 891 892 private boolean _nestedPush(JsStatement statement, boolean needSpace) { 893 boolean push = !(statement instanceof JsBlock); 894 if (push) { 895 if (needSpace) { 896 _space(); 897 } 898 p.indentIn(); 899 _newlineOpt(); 900 } else { 901 _spaceOpt(); 902 } 903 return push; 904 } 905 906 private void _new() { 907 p.print(CHARS_NEW); 908 } 909 910 private void _null() { 911 p.print(CHARS_NULL); 912 } 913 914 private boolean _parenCalc(JsExpression parent, JsExpression child, 915 boolean wrongAssoc) { 916 int parentPrec = JsPrecedenceVisitor.exec(parent); 917 int childPrec = JsPrecedenceVisitor.exec(child); 918 return (parentPrec > childPrec || (parentPrec == childPrec && wrongAssoc)); 919 } 920 921 private boolean _parenPop(JsExpression parent, JsExpression child, 922 boolean wrongAssoc) { 923 boolean doPop = _parenCalc(parent, child, wrongAssoc); 924 if (doPop) { 925 _rparen(); 926 } 927 return doPop; 928 } 929 930 private boolean _parenPopIfCommaExpr(JsExpression x) { 931 boolean doPop = x instanceof JsBinaryOperation 932 && ((JsBinaryOperation) x).getOperator() == JsBinaryOperator.COMMA; 933 if (doPop) { 934 _rparen(); 935 } 936 return doPop; 937 } 938 939 private boolean _parenPopIfConditional(JsExpression x) { 940 boolean doPop = x instanceof JsConditional; 941 if (doPop) { 942 _rparen(); 943 } 944 return doPop; 945 } 946 947 private boolean _parenPopOrSpace(JsExpression parent, JsExpression child, 948 boolean wrongAssoc) { 949 boolean doPop = _parenCalc(parent, child, wrongAssoc); 950 if (doPop) { 951 _rparen(); 952 } else { 953 _space(); 954 } 955 return doPop; 956 } 957 958 private boolean _parenPush(JsExpression parent, JsExpression child, 959 boolean wrongAssoc) { 960 boolean doPush = _parenCalc(parent, child, wrongAssoc); 961 if (doPush) { 962 _lparen(); 963 } 964 return doPush; 965 } 966 967 private boolean _parenPushIfCommaExpr(JsExpression x) { 968 boolean doPush = x instanceof JsBinaryOperation 969 && ((JsBinaryOperation) x).getOperator() == JsBinaryOperator.COMMA; 970 if (doPush) { 971 _lparen(); 972 } 973 return doPush; 974 } 975 976 private boolean _parenPushIfConditional(JsExpression x) { 977 boolean doPush = x instanceof JsConditional; 978 if (doPush) { 979 _lparen(); 980 } 981 return doPush; 982 } 983 984 private boolean _parenPushOrSpace(JsExpression parent, JsExpression child, 985 boolean wrongAssoc) { 986 boolean doPush = _parenCalc(parent, child, wrongAssoc); 987 if (doPush) { 988 _lparen(); 989 } else { 990 _space(); 991 } 992 return doPush; 993 } 994 995 private void _questionMark() { 996 p.print('?'); 997 } 998 999 private void _rbrace() { 1000 p.print('}'); 1001 } 1002 1003 private void _return() { 1004 p.print(CHARS_RETURN); 1005 } 1006 1007 private void _rparen() { 1008 p.print(')'); 1009 } 1010 1011 private void _rsquare() { 1012 p.print(']'); 1013 } 1014 1015 private void _semi() { 1016 p.print(';'); 1017 } 1018 1019 private boolean _sepCommaOptSpace(boolean sep) { 1020 if (sep) { 1021 p.print(','); 1022 _spaceOpt(); 1023 } 1024 return true; 1025 } 1026 1027 private void _slash() { 1028 p.print('/'); 1029 } 1030 1031 private void _space() { 1032 p.print(' '); 1033 } 1034 1035 private void _spaceOpt() { 1036 p.printOpt(' '); 1037 } 1038 1039 private void _switch() { 1040 p.print(CHARS_SWITCH); 1041 } 1042 1043 private void _this() { 1044 p.print(CHARS_THIS); 1045 } 1046 1047 private void _throw() { 1048 p.print(CHARS_THROW); 1049 } 1050 1051 private void _true() { 1052 p.print(CHARS_TRUE); 1053 } 1054 1055 private void _try() { 1056 p.print(CHARS_TRY); 1057 } 1058 1059 private void _var() { 1060 p.print(CHARS_VAR); 1061 } 1062 1063 private void _while() { 1064 p.print(CHARS_WHILE); 1065 } 1066 1067 1069 1076 private void escapeClosingTags(StringBuffer str) { 1077 if (str == null) { 1078 return; 1079 } 1080 1081 int index = 0; 1082 1083 while ((index = str.indexOf("</", index)) != -1) { 1084 str.insert(index + 1, '\\'); 1085 } 1086 } 1087 1088 private void indent() { 1089 p.indentIn(); 1090 } 1091 1092 private void outdent() { 1093 p.indentOut(); 1094 } 1095 1096 1102 private void printStringLiteral(String value) { 1103 1104 char[] chars = value.toCharArray(); 1105 final int n = chars.length; 1106 int quoteCount = 0; 1107 int aposCount = 0; 1108 for (int i = 0; i < n; ++i) { 1109 switch (chars[i]) { 1110 case '"': 1111 ++quoteCount; 1112 break; 1113 case '\'': 1114 ++aposCount; 1115 break; 1116 } 1117 } 1118 1119 StringBuffer result = new StringBuffer (value.length() + 16); 1120 1121 char quoteChar = (quoteCount < aposCount) ? '"' : '\''; 1122 p.print(quoteChar); 1123 1124 for (int i = 0; i < n; ++i) { 1125 char c = chars[i]; 1126 1127 if (' ' <= c && c <= '~' && c != quoteChar && c != '\\') { 1128 result.append(c); 1130 continue; 1131 } 1132 1133 int escape = -1; 1134 switch (c) { 1135 case 0: 1136 escape = '0'; 1137 break; 1138 case '\b': 1139 escape = 'b'; 1140 break; 1141 case '\f': 1142 escape = 'f'; 1143 break; 1144 case '\n': 1145 escape = 'n'; 1146 break; 1147 case '\r': 1148 escape = 'r'; 1149 break; 1150 case '\t': 1151 escape = 't'; 1152 break; 1153 case '"': 1154 escape = '"'; 1155 break; case '\'': 1157 escape = '\''; 1158 break; case '\\': 1160 escape = '\\'; 1161 break; 1162 } 1163 1164 if (escape >= 0) { 1165 result.append('\\'); 1167 result.append((char) escape); 1168 } else { 1169 int hexSize; 1170 if (c < 256) { 1171 result.append("\\x"); 1173 hexSize = 2; 1174 } else { 1175 result.append("\\u"); 1177 hexSize = 4; 1178 } 1179 for (int shift = (hexSize - 1) * 4; shift >= 0; shift -= 4) { 1181 int digit = 0xf & (c >> shift); 1182 result.append(HEX_DIGITS[digit]); 1183 } 1184 } 1185 } 1186 result.append(quoteChar); 1187 escapeClosingTags(result); 1188 p.print(result.toString()); 1189 } 1190} 1191 | Popular Tags |