1 28 29 package org.jruby.ast.visitor.rewriter; 30 31 import java.io.OutputStream ; 32 import java.io.PrintWriter ; 33 import java.io.StringWriter ; 34 import java.io.Writer ; 35 import java.math.BigInteger ; 36 import java.util.ArrayList ; 37 import java.util.Iterator ; 38 import java.util.regex.Matcher ; 39 import java.util.regex.Pattern ; 40 41 import org.jruby.ast.*; 42 import org.jruby.ast.types.INameNode; 43 import org.jruby.ast.visitor.NodeVisitor; 44 import org.jruby.ast.visitor.rewriter.utils.Operators; 45 import org.jruby.ast.visitor.rewriter.utils.ReWriterContext; 46 import org.jruby.evaluator.Instruction; 47 import org.jruby.lexer.yacc.ISourcePosition; 48 import org.jruby.parser.StaticScope; 49 50 56 public class ReWriteVisitor implements NodeVisitor { 57 58 protected final ReWriterContext config; 59 protected final ReWriterFactory factory; 60 61 public ReWriteVisitor(Writer out, String source) { 62 this(new ReWriterContext(new PrintWriter (out), source, new DefaultFormatHelper())); 63 } 64 65 public ReWriteVisitor(OutputStream out, String source) { 66 this(new ReWriterContext(new PrintWriter (out, true), source, new DefaultFormatHelper())); 67 } 68 69 public ReWriteVisitor(ReWriterContext config) { 70 this.config = config; 71 factory = new ReWriterFactory(config); 72 } 73 74 public void flushStream() { 75 config.getOutput().flush(); 76 } 77 78 protected void print(String s) { 79 config.getOutput().print(s); 80 } 81 82 protected void print(char c) { 83 config.getOutput().print(c); 84 } 85 86 protected void print(BigInteger i) { 87 config.getOutput().print(i); 88 } 89 90 protected void print(int i) { 91 config.getOutput().print(i); 92 } 93 94 protected void print(long l) { 95 config.getOutput().print(l); 96 } 97 98 protected void print(double d) { 99 config.getOutput().print(d); 100 } 101 102 private void enterCall() { 103 config.getCallDepth().enterCall(); 104 } 105 106 private void leaveCall() { 107 config.getCallDepth().leaveCall(); 108 } 109 110 private boolean inCall() { 111 return config.getCallDepth().inCall(); 112 } 113 114 protected void printNewlineAndIndentation() { 115 if (config.hasHereDocument()) config.fetchHereDocument().print(); 116 117 print('\n'); 118 config.getIndentor().printIndentation(config.getOutput()); 119 } 120 121 private static boolean isReceiverACallNode(CallNode n) { 122 return (n.getReceiverNode() instanceof CallNode || n.getReceiverNode() instanceof FCallNode); 123 } 124 125 private void printCommentsBefore(Node iVisited) { 126 127 for (Iterator it = iVisited.getComments().iterator(); it.hasNext(); ) { 128 CommentNode n = (CommentNode) it.next(); 129 if(getStartLine(n) < getStartLine(iVisited)) { 130 visitNode(n); 131 printNewlineAndIndentation(); 132 } 133 } 134 } 135 136 protected boolean printCommentsAfter(Node iVisited) { 137 boolean hasComment = false; 138 139 for (Iterator it = iVisited.getComments().iterator(); it.hasNext(); ) { 140 CommentNode n = (CommentNode) it.next(); 141 if(getStartLine(n) >= getEndLine(iVisited)) { 142 print(' '); 143 visitNode(n); 144 hasComment = true; 145 } 146 } 147 148 return hasComment; 149 } 150 151 public void visitNode(Node iVisited) { 152 if (iVisited == null) return; 153 154 printCommentsBefore(iVisited); 155 156 if (iVisited instanceof ArgumentNode) { 157 print(((ArgumentNode) iVisited).getName()); 158 } else { 159 iVisited.accept(this); 160 } 161 162 printCommentsAfter(iVisited); 163 config.setLastPosition(iVisited.getPosition()); 164 } 165 166 public void visitIter(Iterator iterator) { 167 while (iterator.hasNext()) { 168 visitNode((Node) iterator.next()); 169 } 170 } 171 172 private void visitIterAndSkipFirst(Iterator iterator) { 173 iterator.next(); 174 visitIter(iterator); 175 } 176 177 private static boolean isStartOnNewLine(Node first, Node second) { 178 if (first == null || second == null) return false; 179 180 return (getStartLine(first) < getStartLine(second)); 181 } 182 183 private boolean needsParentheses(Node n) { 184 return (n != null && (n.childNodes().size() > 1 || inCall() || firstChild(n) instanceof HashNode) 185 || firstChild(n) instanceof NewlineNode || firstChild(n) instanceof IfNode); 186 } 187 188 private void printCallArguments(Node argsNode, Node iterNode) { 189 if (argsNode != null && argsNode.childNodes().size() < 1 && iterNode == null) return; 190 191 if (argsNode != null && argsNode.childNodes().size() == 1 && 192 firstChild(argsNode) instanceof HashNode && iterNode == null) { 193 HashNode hashNode = (HashNode) firstChild(argsNode); 194 if(hashNode.getListNode().childNodes().size() < 1) { 195 print("({})"); 196 } else { 197 print(' '); 198 printHashNodeContent(hashNode); 199 } 200 return; 201 } 202 203 boolean paranthesesPrinted = needsParentheses(argsNode) 204 || (argsNode == null && iterNode != null && iterNode instanceof BlockPassNode) 205 || (argsNode != null && argsNode.childNodes().size() > 0 && iterNode != null); 206 207 if (paranthesesPrinted) { 208 print('('); 209 } else if (argsNode != null) { 210 print(config.getFormatHelper().beforeCallArguments()); 211 } 212 213 if (firstChild(argsNode) instanceof NewlineNode) { 214 config.setSkipNextNewline(true); 215 } 216 217 enterCall(); 218 219 if (argsNode instanceof SplatNode) { 220 visitNode(argsNode); 221 } else if (argsNode != null) { 222 visitAndPrintWithSeparator(argsNode.childNodes().iterator()); 223 } 224 225 if (iterNode instanceof BlockPassNode) { 226 if (argsNode != null) print(config.getFormatHelper().getListSeparator()); 227 228 print('&'); 229 visitNode(((BlockPassNode) iterNode).getBodyNode()); 230 } 231 232 if (paranthesesPrinted) { 233 print(')'); 234 } else { 235 print(config.getFormatHelper().afterCallArguments()); 236 } 237 238 leaveCall(); 239 } 240 241 public void visitAndPrintWithSeparator(Iterator it) { 242 while (it.hasNext()) { 243 Node n = (Node) it.next(); 244 factory.createIgnoreCommentsReWriteVisitor().visitNode(n); 245 if (it.hasNext()) 246 print(config.getFormatHelper().getListSeparator()); 247 if(n.hasComments()) { 248 factory.createReWriteVisitor().visitIter(n.getComments().iterator()); 249 printNewlineAndIndentation(); 250 } 251 } 252 } 253 254 public Instruction visitAliasNode(AliasNode iVisited) { 255 print("alias "); 256 print(iVisited.getNewName()); 257 print(' '); 258 print(iVisited.getOldName()); 259 printCommentsAtEnd(iVisited); 260 return null; 261 } 262 263 private boolean sourceRangeEquals(int start, int stop, String compare) { 264 return (stop <= config.getSource().length() && sourceSubStringEquals(start, stop - start, compare)); 265 } 266 267 private boolean sourceRangeContains(ISourcePosition pos, String searched) { 268 return pos.getStartOffset() < config.getSource().length() 269 && pos.getEndOffset() < config.getSource().length() + 1 270 && config.getSource().substring(pos.getStartOffset(), pos.getEndOffset()).indexOf(searched) > -1; 271 } 272 public Instruction visitAndNode(AndNode iVisited) { 273 enterCall(); 274 visitNode(iVisited.getFirstNode()); 275 276 if (sourceRangeContains(iVisited.getPosition(), "&&")) { 277 print(" && "); 278 } else { 279 print(" and "); 280 } 281 visitNode(iVisited.getSecondNode()); 282 leaveCall(); 283 return null; 284 } 285 286 287 private ArrayList collectAllArguments(ArgsNode iVisited) { 288 ArrayList arguments = new ArrayList (); 289 290 if (iVisited.getArgs() != null) arguments.addAll(iVisited.getArgs().childNodes()); 291 292 if (iVisited.getOptArgs() != null) arguments.addAll(iVisited.getOptArgs().childNodes()); 293 294 if (iVisited.getRestArg() > 0) { 295 arguments.add(new ConstNode(null, '*' + config.getLocalVariables().getLocalVariable(iVisited.getRestArg()))); 296 } 297 298 if (iVisited.getBlockArgNode() != null) arguments.add(iVisited.getBlockArgNode()); 299 300 return arguments; 301 } 302 303 private boolean hasNodeCommentsAtEnd(Node n) { 304 for (Iterator it = n.getComments().iterator(); it.hasNext(); ) { 305 Node comment = (Node) it.next(); 306 307 if (getStartLine(comment) == getStartLine(n)) return true; 308 } 309 310 return false; 311 } 312 313 private void printCommentsInArgs(Node n, boolean hasNext) { 314 if (hasNodeCommentsAtEnd(n) && hasNext) print(","); 315 316 if (printCommentsAfter(n) && hasNext) { 317 printNewlineAndIndentation(); 318 } else if (hasNext) { 319 print(config.getFormatHelper().getListSeparator()); 320 } 321 } 322 323 public Instruction visitArgsNode(ArgsNode iVisited) { 324 325 for (Iterator it = collectAllArguments(iVisited).iterator(); it.hasNext(); ) { 326 Node n = (Node) it.next(); 327 328 if (n instanceof ArgumentNode) { 329 print(((ArgumentNode) n).getName()); 330 printCommentsInArgs(n, it.hasNext()); 331 } else { 332 visitNode(n); 333 if (it.hasNext()) print(config.getFormatHelper().getListSeparator()); 334 } 335 336 if (!it.hasNext()) print(config.getFormatHelper().afterMethodArguments()); 337 } 338 339 return null; 340 } 341 342 public Instruction visitArgsCatNode(ArgsCatNode iVisited) { 343 print("["); 344 visitAndPrintWithSeparator(iVisited.getFirstNode().childNodes().iterator()); 345 print(config.getFormatHelper().getListSeparator()); 346 print("*"); 347 visitNode(iVisited.getSecondNode()); 348 print("]"); 349 return null; 350 } 351 352 public Instruction visitArrayNode(ArrayNode iVisited) { 353 print('['); 354 enterCall(); 355 visitAndPrintWithSeparator(iVisited.iterator()); 356 leaveCall(); 357 print(']'); 358 return null; 359 } 360 361 public Instruction visitBackRefNode(BackRefNode iVisited) { 362 print('$'); 363 print(iVisited.getType()); 364 return null; 365 } 366 367 public Instruction visitBeginNode(BeginNode iVisited) { 368 print("begin"); 369 visitNodeInIndentation(iVisited.getBodyNode()); 370 printNewlineAndIndentation(); 371 print("end"); 372 return null; 373 } 374 375 public Instruction visitBignumNode(BignumNode iVisited) { 376 print(iVisited.getValue()); 377 return null; 378 } 379 380 public Instruction visitBlockArgNode(BlockArgNode iVisited) { 381 print('&'); 382 print(iVisited.getName()); 383 return null; 384 } 385 386 public Instruction visitBlockNode(BlockNode iVisited) { 387 visitIter(iVisited.iterator()); 388 return null; 389 } 390 391 public static int getLocalVarIndex(Node n) { 392 return n instanceof LocalVarNode ? ((LocalVarNode) n).getIndex() : -1; 393 } 394 395 public Instruction visitBlockPassNode(BlockPassNode iVisited) { 396 visitNode(iVisited.getBodyNode()); 397 return null; 398 } 399 400 public Instruction visitBreakNode(BreakNode iVisited) { 401 print("break"); 402 return null; 403 } 404 405 public Instruction visitConstDeclNode(ConstDeclNode iVisited) { 406 printAsgnNode(iVisited); 407 return null; 408 } 409 410 public Instruction visitClassVarAsgnNode(ClassVarAsgnNode iVisited) { 411 printAsgnNode(iVisited); 412 return null; 413 } 414 415 public Instruction visitClassVarDeclNode(ClassVarDeclNode iVisited) { 416 printAsgnNode(iVisited); 417 return null; 418 } 419 420 public Instruction visitClassVarNode(ClassVarNode iVisited) { 421 print(iVisited.getName()); 422 return null; 423 } 424 425 private boolean isNumericNode(Node n) { 426 return (n != null && (n instanceof FixnumNode || n instanceof BignumNode)); 427 } 428 429 private boolean isNameAnOperator(String name) { 430 return Operators.contain(name); 431 } 432 433 private boolean printSpaceInsteadOfDot(CallNode n) { 434 return (isNameAnOperator(n.getName()) && !(n.getArgsNode().childNodes().size() > 1)); 435 } 436 437 protected void printAssignmentOperator(){ 438 print(config.getFormatHelper().beforeAssignment()); 439 print("="); 440 print(config.getFormatHelper().afterAssignment()); 441 } 442 443 private Instruction printIndexAssignment(AttrAssignNode iVisited) { 444 enterCall(); 445 visitNode(iVisited.getReceiverNode()); 446 leaveCall(); 447 print('['); 448 visitNode(firstChild(iVisited.getArgsNode())); 449 print("]"); 450 printAssignmentOperator(); 451 if (iVisited.getArgsNode().childNodes().size() > 1) 452 visitNode((Node) iVisited.getArgsNode().childNodes().get(1)); 453 return null; 454 } 455 456 private Instruction printIndexAccess(CallNode visited) { 457 enterCall(); 458 visitNode(visited.getReceiverNode()); 459 leaveCall(); 460 print('['); 461 if (visited.getArgsNode() != null) { 462 visitAndPrintWithSeparator(visited.getArgsNode().childNodes().iterator()); 463 } 464 print("]"); 465 return null; 466 } 467 468 private Instruction printNegativNumericNode(CallNode visited) { 469 print('-'); 470 visitNode(visited.getReceiverNode()); 471 return null; 472 } 473 474 private boolean isNegativeNumericNode(CallNode visited) { 475 return isNumericNode(visited.getReceiverNode()) && visited.getName().equals("-@"); 476 } 477 478 private void printCallReceiverNode(CallNode iVisited) { 479 if (iVisited.getReceiverNode() instanceof HashNode) print('('); 480 481 if (isReceiverACallNode(iVisited) && !printSpaceInsteadOfDot(iVisited)) { 482 enterCall(); 483 visitNewlineInParentheses(iVisited.getReceiverNode()); 484 leaveCall(); 485 } else { 486 visitNewlineInParentheses(iVisited.getReceiverNode()); 487 } 488 489 if (iVisited.getReceiverNode() instanceof HashNode) print(')'); 490 } 491 492 protected boolean inMultipleAssignment() { 493 return false; 494 } 495 496 public Instruction visitCallNode(CallNode iVisited) { 497 if (isNegativeNumericNode(iVisited)) return printNegativNumericNode(iVisited); 498 499 if (iVisited.getName().equals("[]")) return printIndexAccess(iVisited); 500 501 printCallReceiverNode(iVisited); 502 503 print(printSpaceInsteadOfDot(iVisited) ? ' ' : '.'); 504 505 if (inMultipleAssignment() && iVisited.getName().endsWith("=")) { 506 print(iVisited.getName().substring(0, iVisited.getName().length() - 1)); 507 } else { 508 print(iVisited.getName()); 509 } 510 511 if (isNameAnOperator(iVisited.getName())) { 512 if (firstChild(iVisited.getArgsNode()) instanceof NewlineNode) print(' '); 513 514 config.getCallDepth().disableCallDepth(); 515 } 516 printCallArguments(iVisited.getArgsNode(), iVisited.getIterNode()); 517 518 if (isNameAnOperator(iVisited.getName())) config.getCallDepth().enableCallDepth(); 519 if (!(iVisited.getIterNode() instanceof BlockPassNode)) visitNode(iVisited.getIterNode()); 520 521 return null; 522 } 523 524 public Instruction visitCaseNode(CaseNode iVisited) { 525 print("case "); 526 visitNode(iVisited.getCaseNode()); 527 visitNode(iVisited.getFirstWhenNode()); 528 printNewlineAndIndentation(); 529 print("end"); 530 return null; 531 } 532 533 private boolean printCommentsIn(Node iVisited) { 534 boolean hadComment = false; 535 for (Iterator it = iVisited.getComments().iterator(); it.hasNext(); ) { 536 CommentNode n = (CommentNode) it.next(); 537 538 if(getStartLine(n) > getStartLine(iVisited) && getEndLine(n) < getEndLine(iVisited)) { 539 hadComment = true; 540 visitNode(n); 541 printNewlineAndIndentation(); 542 } 543 } 544 545 return hadComment; 546 } 547 548 public Instruction visitClassNode(ClassNode iVisited) { 549 550 print("class "); 551 visitNode(iVisited.getCPath()); 552 if (iVisited.getSuperNode() != null) { 553 print(" < "); 554 visitNode(iVisited.getSuperNode()); 555 } 556 557 new ClassBodyWriter(this, iVisited.getBodyNode()).write(); 558 559 printNewlineAndIndentation(); 560 printCommentsIn(iVisited); 561 562 print("end"); 563 return null; 564 } 565 566 public Instruction visitColon2Node(Colon2Node iVisited) { 567 if (iVisited.getLeftNode() != null) { 568 visitNode(iVisited.getLeftNode()); 569 print("::"); 570 } 571 print(iVisited.getName()); 572 return null; 573 } 574 575 public Instruction visitColon3Node(Colon3Node iVisited) { 576 print("::"); 577 print(iVisited.getName()); 578 return null; 579 } 580 581 public Instruction visitConstNode(ConstNode iVisited) { 582 print(iVisited.getName()); 583 return null; 584 } 585 586 public Instruction visitDAsgnNode(DAsgnNode iVisited) { 587 printAsgnNode(iVisited); 588 return null; 589 } 590 591 public Instruction visitDRegxNode(DRegexpNode iVisited) { 592 config.getPrintQuotesInString().set(false); 593 print(getFirstRegexpEnclosure(iVisited)); 594 factory.createDRegxReWriteVisitor().visitIter(iVisited.childNodes().iterator()); 595 print(getSecondRegexpEnclosure(iVisited)); 596 printRegexpOptions(iVisited.getOptions()); 597 config.getPrintQuotesInString().revert(); 598 return null; 599 } 600 601 private Instruction createHereDocument(DStrNode iVisited) { 602 config.getPrintQuotesInString().set(false); 603 print("<<-EOF"); 604 StringWriter writer = new StringWriter (); 605 PrintWriter oldOut = config.getOutput(); 606 config.setOutput(new PrintWriter (writer)); 607 608 for (Iterator it = iVisited.childNodes().iterator(); it.hasNext(); ) { 609 factory.createHereDocReWriteVisitor().visitNode((Node) it.next()); 610 611 if (it.hasNext()) config.setSkipNextNewline(true); 612 } 613 614 config.setOutput(oldOut); 615 config.depositHereDocument(writer.getBuffer().toString()); 616 config.getPrintQuotesInString().revert(); 617 618 return null; 619 } 620 621 public Instruction visitDStrNode(DStrNode iVisited) { 622 623 if (firstChild(iVisited) instanceof StrNode && stringIsHereDocument((StrNode) firstChild(iVisited))) { 624 return createHereDocument(iVisited); 625 } 626 627 if (config.getPrintQuotesInString().isTrue()) print(getSeparatorForStr(iVisited)); 628 629 config.getPrintQuotesInString().set(false); 630 leaveCall(); 631 for (Iterator it = iVisited.childNodes().iterator(); it.hasNext(); ) { 632 visitNode((Node) it.next()); 633 } 634 enterCall(); 635 config.getPrintQuotesInString().revert(); 636 637 if (config.getPrintQuotesInString().isTrue()) print(getSeparatorForStr(iVisited)); 638 639 return null; 640 } 641 642 public Instruction visitDSymbolNode(DSymbolNode iVisited) { 643 print(':'); 644 if (config.getPrintQuotesInString().isTrue()) print(getSeparatorForSym(iVisited)); 645 646 config.getPrintQuotesInString().set(false); 647 leaveCall(); 648 for (Iterator it = iVisited.childNodes().iterator(); it.hasNext(); ) { 649 visitNode((Node) it.next()); 650 } 651 enterCall(); 652 config.getPrintQuotesInString().revert(); 653 654 if (config.getPrintQuotesInString().isTrue()) print(getSeparatorForSym(iVisited)); 655 return null; 656 } 657 658 public Instruction visitDVarNode(DVarNode iVisited) { 659 print(iVisited.getName()); 660 return null; 661 } 662 663 public Instruction visitDXStrNode(DXStrNode iVisited) { 664 config.getPrintQuotesInString().set(false); 665 print("%x{"); 666 visitIter(iVisited.childNodes().iterator()); 667 print('}'); 668 config.getPrintQuotesInString().revert(); 669 return null; 670 } 671 672 public Instruction visitDefinedNode(DefinedNode iVisited) { 673 print("defined? "); 674 enterCall(); 675 visitNode(iVisited.getExpressionNode()); 676 leaveCall(); 677 return null; 678 } 679 680 private boolean hasArguments(Node n) { 681 if (n instanceof ArgsNode) { 682 ArgsNode args = (ArgsNode) n; 683 return (args.getArgs() != null || args.getOptArgs() != null 684 || args.getBlockArgNode() != null || args.getRestArg() > 0 ); 685 } else if (n instanceof ArrayNode && n.childNodes().isEmpty()) { 686 return false; 687 } 688 return true; 689 } 690 691 protected void printCommentsAtEnd(Node n) { 692 for (Iterator it = n.getComments().iterator(); it.hasNext(); ) { 693 Node comment = (Node) it.next(); 694 695 if(getStartLine(n) == getStartLine(comment)) { 696 print(' '); 697 visitNode(comment); 698 } 699 } 700 } 701 702 private void printDefNode(Node parent, String name, Node args, StaticScope scope, Node bodyNode) { 703 print(name); 704 printCommentsAtEnd(parent); 705 config.getLocalVariables().addLocalVariable(scope); 706 707 if (hasArguments(args)) { 708 print(config.getFormatHelper().beforeMethodArguments()); 709 visitNode(args); 710 } 711 visitNode(bodyNode); 712 config.getIndentor().outdent(); 713 printNewlineAndIndentation(); 714 printCommentsIn(parent); 715 print("end"); 716 } 717 718 public Instruction visitDefnNode(DefnNode iVisited) { 719 config.getIndentor().indent(); 720 print("def "); 721 printDefNode(iVisited, iVisited.getName(), iVisited.getArgsNode(), iVisited.getScope(), iVisited.getBodyNode()); 722 return null; 723 } 724 725 public Instruction visitDefsNode(DefsNode iVisited) { 726 config.getIndentor().indent(); 727 print("def "); 728 visitNode(iVisited.getReceiverNode()); 729 print('.'); 730 printDefNode(iVisited, iVisited.getName(), iVisited.getArgsNode(), iVisited.getScope(), iVisited.getBodyNode()); 731 return null; 732 } 733 734 public Instruction visitDotNode(DotNode iVisited) { 735 enterCall(); 736 visitNode(iVisited.getBeginNode()); 737 print(".."); 738 if (iVisited.isExclusive()) print('.'); 739 visitNode(iVisited.getEndNode()); 740 leaveCall(); 741 return null; 742 } 743 744 public Instruction visitEnsureNode(EnsureNode iVisited) { 745 visitNode(iVisited.getBodyNode()); 746 config.getIndentor().outdent(); 747 printNewlineAndIndentation(); 748 print("ensure"); 749 visitNodeInIndentation(iVisited.getEnsureNode()); 750 config.getIndentor().indent(); 751 return null; 752 } 753 754 public Instruction visitEvStrNode(EvStrNode iVisited) { 755 print('#'); 756 if (!(iVisited.getBody() instanceof NthRefNode)) print('{'); 757 config.getPrintQuotesInString().set(true); 758 visitNode(unwrapNewlineNode(iVisited.getBody())); 759 config.getPrintQuotesInString().revert(); 760 if (!(iVisited.getBody() instanceof NthRefNode)) print('}'); 761 return null; 762 } 763 764 private Node unwrapNewlineNode(Node node) { 765 return node instanceof NewlineNode ? ((NewlineNode) node).getNextNode() : node; 766 } 767 768 public Instruction visitFCallNode(FCallNode iVisited) { 769 print(iVisited.getName()); 770 771 if (iVisited.getIterNode() != null) config.getCallDepth().enterCall(); 772 773 printCallArguments(iVisited.getArgsNode(), iVisited.getIterNode()); 774 775 if (iVisited.getIterNode() != null) config.getCallDepth().leaveCall(); 776 777 if (!(iVisited.getIterNode() instanceof BlockPassNode)) visitNode(iVisited.getIterNode()); 778 779 return null; 780 } 781 782 public Instruction visitFalseNode(FalseNode iVisited) { 783 print("false"); 784 return null; 785 } 786 787 public Instruction visitFixnumNode(FixnumNode iVisited) { 788 print(iVisited.getValue()); 789 return null; 790 } 791 792 public Instruction visitFlipNode(FlipNode iVisited) { 793 enterCall(); 794 visitNode(iVisited.getBeginNode()); 795 print(" .."); 796 if (iVisited.isExclusive()) print('.'); 797 print(' '); 798 visitNode(iVisited.getEndNode()); 799 leaveCall(); 800 return null; 801 } 802 803 public Instruction visitFloatNode(FloatNode iVisited) { 804 print(iVisited.getValue()); 805 return null; 806 } 807 808 public Instruction visitForNode(ForNode iVisited) { 809 print("for "); 810 visitNode(iVisited.getVarNode()); 811 print(" in "); 812 visitNode(iVisited.getIterNode()); 813 visitNodeInIndentation(iVisited.getBodyNode()); 814 printNewlineAndIndentation(); 815 print("end"); 816 return null; 817 } 818 819 public Instruction visitGlobalAsgnNode(GlobalAsgnNode iVisited) { 820 printAsgnNode(iVisited); 821 return null; 822 } 823 824 public Instruction visitGlobalVarNode(GlobalVarNode iVisited) { 825 print(iVisited.getName()); 826 return null; 827 } 828 829 private void printHashNodeContent(HashNode iVisited) { 830 print(config.getFormatHelper().beforeHashContent()); 831 if (iVisited.getListNode() != null) { 832 for (Iterator it = iVisited.getListNode().childNodes().iterator(); it.hasNext(); ) { 833 visitNode((Node) it.next()); 834 print(config.getFormatHelper().hashAssignment()); 835 visitNode((Node) it.next()); 836 837 if (it.hasNext()) print(config.getFormatHelper().getListSeparator()); 838 } 839 } 840 print(config.getFormatHelper().afterHashContent()); 841 } 842 843 public Instruction visitHashNode(HashNode iVisited) { 844 print('{'); 845 printHashNodeContent(iVisited); 846 print('}'); 847 return null; 848 } 849 850 private void printAsgnNode(AssignableNode n) { 851 print(((INameNode) n).getName()); 852 if (n.getValueNode() == null) return; 853 printAssignmentOperator(); 854 visitNewlineInParentheses(n.getValueNode()); 855 } 856 857 public Instruction visitInstAsgnNode(InstAsgnNode iVisited) { 858 printAsgnNode(iVisited); 859 return null; 860 } 861 862 public Instruction visitInstVarNode(InstVarNode iVisited) { 863 print(iVisited.getName()); 864 return null; 865 } 866 867 875 private Node printElsIfNodes(Node iVisited) { 876 if (iVisited != null && iVisited instanceof IfNode) { 877 IfNode n = (IfNode) iVisited; 878 printNewlineAndIndentation(); 879 print("elsif "); 880 visitNode(n.getCondition()); 881 visitNodeInIndentation(n.getThenBody()); 882 return printElsIfNodes(n.getElseBody()); 883 } 884 885 return iVisited != null ? iVisited : null; 886 } 887 888 private Instruction printShortIfStatement(IfNode n) { 889 if (n.getThenBody() == null) { 890 visitNode(n.getElseBody()); 891 print(" unless "); 892 visitNode(n.getCondition()); 893 } else { 894 enterCall(); 895 factory.createShortIfNodeReWriteVisitor().visitNode(n.getCondition()); 896 print(" ? "); 897 factory.createShortIfNodeReWriteVisitor().visitNode(n.getThenBody()); 898 print(" : "); 899 factory.createShortIfNodeReWriteVisitor().visitNewlineInParentheses(n.getElseBody()); 900 leaveCall(); 901 } 902 return null; 903 } 904 905 private boolean isAssignment(Node n) { 906 return (n instanceof DAsgnNode || n instanceof GlobalAsgnNode 907 || n instanceof InstAsgnNode || n instanceof LocalAsgnNode || n instanceof ClassVarAsgnNode); 908 } 909 910 private boolean sourceSubStringEquals(int offset, int length, String str) { 911 return config.getSource().length() >= offset + length 912 && config.getSource().substring(offset, offset + length).equals(str); 913 } 914 915 private boolean isShortIfStatement(IfNode iVisited) { 916 return (isOnSingleLine(iVisited.getCondition(), iVisited.getElseBody()) 917 && !(iVisited.getElseBody() instanceof IfNode) 918 && !sourceSubStringEquals(getStartOffset(iVisited), 2, "if")); 919 } 920 921 public Instruction visitIfNode(IfNode iVisited) { 922 923 if (isShortIfStatement(iVisited)) return printShortIfStatement(iVisited); 924 925 print("if "); 926 927 if (isAssignment(iVisited.getCondition())) enterCall(); 928 929 visitNewlineInParentheses(iVisited.getCondition()); 931 932 if (isAssignment(iVisited.getCondition())) leaveCall(); 933 934 config.getIndentor().indent(); 935 if (!isStartOnNewLine(iVisited.getCondition(), iVisited.getThenBody()) && iVisited.getThenBody() != null) { 938 printNewlineAndIndentation(); 939 } 940 941 visitNode(iVisited.getThenBody()); 942 config.getIndentor().outdent(); 943 Node elseNode = printElsIfNodes(iVisited.getElseBody()); 944 945 if (elseNode != null) { 946 printNewlineAndIndentation(); 947 print("else"); 948 config.getIndentor().indent(); 949 visitNode(elseNode); 950 config.getIndentor().outdent(); 951 } 952 printNewlineAndIndentation(); 953 print("end"); 954 return null; 955 } 956 957 private boolean isOnSingleLine(Node n) { 958 return isOnSingleLine(n, n); 959 } 960 961 private boolean isOnSingleLine(Node n1, Node n2) { 962 if (n1 == null || n2 == null) return false; 963 964 return (getStartLine(n1) == getEndLine(n2)); 965 } 966 967 private boolean printIterVarNode(IterNode n) { 968 if (n.getVarNode() == null) return false; 969 970 print('|'); 971 visitNode(n.getVarNode()); 972 print('|'); 973 974 return true; 975 } 976 977 public Instruction visitIterNode(IterNode iVisited) { 978 if (isOnSingleLine(iVisited)) { 979 print(config.getFormatHelper().beforeIterBrackets()); 980 print("{"); 981 print(config.getFormatHelper().beforeIterVars()); 982 if(printIterVarNode(iVisited)) print(config.getFormatHelper().afterIterVars()); 983 config.setSkipNextNewline(true); 984 visitNode(iVisited.getBodyNode()); 985 print(config.getFormatHelper().beforeClosingIterBrackets()); 986 print('}'); 987 } else { 988 print(" do "); 989 printIterVarNode(iVisited); 990 visitNodeInIndentation(iVisited.getBodyNode()); 991 printNewlineAndIndentation(); 992 print("end"); 993 } 994 return null; 995 } 996 997 public Instruction visitLocalAsgnNode(LocalAsgnNode iVisited) { 998 config.getLocalVariables().addLocalVariable(iVisited.getIndex(), iVisited.getName()); 999 printAsgnNode(iVisited); 1000 return null; 1001 } 1002 1003 public Instruction visitLocalVarNode(LocalVarNode iVisited) { 1004 print(iVisited.getName()); 1005 return null; 1006 } 1007 1008 public Instruction visitMultipleAsgnNode(MultipleAsgnNode iVisited) { 1009 if (iVisited.getHeadNode() != null) { 1010 factory.createMultipleAssignmentReWriteVisitor().visitAndPrintWithSeparator(iVisited.getHeadNode().childNodes().iterator()); 1011 } 1012 if (iVisited.getValueNode() == null) { 1013 visitNode(iVisited.getArgsNode()); 1014 return null; 1015 } 1016 print(config.getFormatHelper().beforeAssignment()); 1017 print("="); 1018 print(config.getFormatHelper().afterAssignment()); 1019 enterCall(); 1020 if (iVisited.getValueNode() instanceof ArrayNode) { 1021 visitAndPrintWithSeparator(iVisited.getValueNode().childNodes().iterator()); 1022 } else { 1023 visitNode(iVisited.getValueNode()); 1024 } 1025 leaveCall(); 1026 return null; 1027 } 1028 1029 public Instruction visitMatch2Node(Match2Node iVisited) { 1030 visitNode(iVisited.getReceiverNode()); 1031 print(config.getFormatHelper().matchOperator()); 1032 enterCall(); 1033 visitNode(iVisited.getValueNode()); 1034 leaveCall(); 1035 return null; 1036 } 1037 1038 public Instruction visitMatch3Node(Match3Node iVisited) { 1039 visitNode(iVisited.getValueNode()); 1040 print(config.getFormatHelper().matchOperator()); 1041 visitNode(iVisited.getReceiverNode()); 1042 return null; 1043 } 1044 1045 public Instruction visitMatchNode(MatchNode iVisited) { 1046 visitNode(iVisited.getRegexpNode()); 1047 return null; 1048 } 1049 1050 public Instruction visitModuleNode(ModuleNode iVisited) { 1051 print("module "); 1052 config.getIndentor().indent(); 1053 visitNode(iVisited.getCPath()); 1054 visitNode(iVisited.getBodyNode()); 1055 config.getIndentor().outdent(); 1056 printNewlineAndIndentation(); 1057 print("end"); 1058 return null; 1059 } 1060 1061 public Instruction visitNewlineNode(NewlineNode iVisited) { 1062 if (config.isSkipNextNewline()) { 1063 config.setSkipNextNewline(false); 1064 } else { 1065 printNewlineAndIndentation(); 1066 } 1067 visitNode(iVisited.getNextNode()); 1068 return null; 1069 } 1070 1071 public Instruction visitNextNode(NextNode iVisited) { 1072 print("next"); 1073 return null; 1074 } 1075 1076 public Instruction visitNilNode(NilNode iVisited) { 1077 print("nil"); 1078 return null; 1079 } 1080 1081 public Instruction visitNotNode(NotNode iVisited) { 1082 if (iVisited.getConditionNode() instanceof CallNode) enterCall(); 1083 1084 print(sourceRangeContains(iVisited.getPosition(), "not") ? "not " : "!"); 1085 visitNewlineInParentheses(iVisited.getConditionNode()); 1086 1087 if (iVisited.getConditionNode() instanceof CallNode) leaveCall(); 1088 1089 return null; 1090 } 1091 1092 public Instruction visitNthRefNode(NthRefNode iVisited) { 1093 print('$'); 1094 print(iVisited.getMatchNumber()); 1095 return null; 1096 } 1097 1098 private boolean isSimpleNode(Node n) { 1099 return (n instanceof LocalVarNode || n instanceof AssignableNode 1100 || n instanceof InstVarNode || n instanceof ClassVarNode 1101 || n instanceof GlobalVarNode || n instanceof ConstDeclNode 1102 || n instanceof VCallNode || isNumericNode(n)); 1103 } 1104 1105 public Instruction visitOpElementAsgnNode(OpElementAsgnNode iVisited) { 1106 1107 if (!isSimpleNode(iVisited.getReceiverNode())) { 1108 visitNewlineInParentheses(iVisited.getReceiverNode()); 1109 } else { 1110 visitNode(iVisited.getReceiverNode()); 1111 } 1112 1113 visitNode(iVisited.getArgsNode()); 1114 print(' '); 1115 print(iVisited.getOperatorName()); 1116 print("="); 1117 print(config.getFormatHelper().afterAssignment()); 1118 visitNode(iVisited.getValueNode()); 1119 return null; 1120 } 1121 1122 public Instruction visitOpAsgnNode(OpAsgnNode iVisited) { 1123 visitNode(iVisited.getReceiverNode()); 1124 print('.'); 1125 print(iVisited.getVariableName()); 1126 print(' '); 1127 print(iVisited.getOperatorName()); 1128 print("="); 1129 print(config.getFormatHelper().afterAssignment()); 1130 visitNode(iVisited.getValueNode()); 1131 return null; 1132 } 1133 1134 private void printOpAsgnNode(Node n, String operator) { 1135 enterCall(); 1136 1137 print(((INameNode) n).getName()); 1138 print(config.getFormatHelper().beforeAssignment()); 1139 print(operator); 1140 print(config.getFormatHelper().afterAssignment()); 1141 visitNode(((AssignableNode) n).getValueNode()); 1142 1143 leaveCall(); 1144 } 1145 1146 public Instruction visitOpAsgnAndNode(OpAsgnAndNode iVisited) { 1147 printOpAsgnNode(iVisited.getSecondNode(), "&&="); 1148 return null; 1149 } 1150 1151 public Instruction visitOpAsgnOrNode(OpAsgnOrNode iVisited) { 1152 printOpAsgnNode(iVisited.getSecondNode(), "||="); 1153 return null; 1154 } 1155 1156 public Instruction visitOptNNode(OptNNode iVisited) { 1157 return null; 1160 } 1161 1162 public Instruction visitOrNode(OrNode iVisited) { 1163 enterCall(); 1164 visitNode(iVisited.getFirstNode()); 1165 leaveCall(); 1166 1167 print(sourceRangeContains(iVisited.getPosition(), "||") ? " || " : " or "); 1168 1169 enterCall(); 1170 visitNewlineInParentheses(iVisited.getSecondNode()); 1171 leaveCall(); 1172 1173 return null; 1174 } 1175 1176 public Instruction visitPostExeNode(PostExeNode iVisited) { 1177 return null; 1180 } 1181 1182 public Instruction visitRedoNode(RedoNode iVisited) { 1183 print("redo"); 1184 return null; 1185 } 1186 1187 private String getFirstRegexpEnclosure(Node n) { 1188 return isSpecialRegexNotation(n) ? "%r(" : "/"; 1189 } 1190 1191 private String getSecondRegexpEnclosure(Node n) { 1192 return isSpecialRegexNotation(n) ? ")" : "/"; 1193 } 1194 1195 private boolean isSpecialRegexNotation(Node n) { 1196 return getStartOffset(n) >= 2 1197 && !(config.getSource().length() < getStartOffset(n)) 1198 && config.getSource().charAt(getStartOffset(n) - 3) == '%'; 1199 } 1200 1201 private void printRegexpOptions(int option) { 1202 if ((option & 1) == 1) print('i'); 1203 if ((option & 2) == 2) print('x'); 1204 if ((option & 4) == 4) print('m'); 1205 } 1206 1207 public Instruction visitRegexpNode(RegexpNode iVisited) { 1208 print(getFirstRegexpEnclosure(iVisited)); 1209 print(iVisited.getValue().toString()); 1210 print(getSecondRegexpEnclosure(iVisited)); 1211 printRegexpOptions(iVisited.getOptions()); 1212 return null; 1213 } 1214 1215 public static Node firstChild(Node n) { 1216 if (n == null || n.childNodes().size() <= 0) return null; 1217 1218 return (Node) n.childNodes().get(0); 1219 } 1220 1221 public Instruction visitRescueBodyNode(RescueBodyNode iVisited) { 1222 if (config.getLastPosition().getStartLine() == getEndLine(iVisited.getBodyNode())) { 1223 print(" rescue "); 1224 } else { 1225 print("rescue"); 1226 } 1227 1228 if (iVisited.getExceptionNodes() != null) { 1229 printExceptionNode(iVisited); 1230 } else { 1231 visitNodeInIndentation(iVisited.getBodyNode()); 1232 } 1233 1234 if (iVisited.getOptRescueNode() != null) printNewlineAndIndentation(); 1235 1236 visitNode(iVisited.getOptRescueNode()); 1237 return null; 1238 } 1239 1240 private void printExceptionNode(RescueBodyNode n) { 1241 if (n.getExceptionNodes() == null) return; 1242 1243 print(' '); 1244 visitNode(firstChild(n.getExceptionNodes())); 1245 1246 Node firstBodyNode = n.getBodyNode(); 1247 if (n.getBodyNode() instanceof BlockNode) firstBodyNode = firstChild(n.getBodyNode()); 1248 1249 if (firstBodyNode instanceof AssignableNode) { 1252 print(config.getFormatHelper().beforeAssignment()); 1253 print("=>"); 1254 print(config.getFormatHelper().afterAssignment()); 1255 print(((INameNode) firstBodyNode).getName()); 1256 if (firstBodyNode instanceof LocalAsgnNode) 1257 config.getLocalVariables().addLocalVariable(((LocalAsgnNode) firstBodyNode).getIndex(), 1258 ((LocalAsgnNode) firstBodyNode).getName()); 1259 1260 config.getIndentor().indent(); 1261 visitIterAndSkipFirst(n.getBodyNode().childNodes().iterator()); 1262 config.getIndentor().outdent(); 1263 } else { 1264 visitNodeInIndentation(n.getBodyNode()); 1265 } 1266 } 1267 1268 public Instruction visitRescueNode(RescueNode iVisited) { 1269 visitNode(iVisited.getBodyNode()); 1270 config.getIndentor().outdent(); 1271 1272 if (iVisited.getRescueNode().getBodyNode() != null 1273 && getStartLine(iVisited) != getEndLine(iVisited.getRescueNode().getBodyNode())) { 1274 printNewlineAndIndentation(); 1275 } 1276 1277 if (iVisited.getRescueNode().getBodyNode() == null) { 1278 printNewlineAndIndentation(); 1279 print("rescue"); 1280 printExceptionNode(iVisited.getRescueNode()); 1281 } else { 1282 visitNode(iVisited.getRescueNode()); 1283 } 1284 1285 if (iVisited.getElseNode() != null) { 1286 printNewlineAndIndentation(); 1287 print("else"); 1288 visitNodeInIndentation(iVisited.getElseNode()); 1289 } 1290 1291 config.getIndentor().indent(); 1292 return null; 1293 } 1294 1295 public Instruction visitRetryNode(RetryNode iVisited) { 1296 print("retry"); 1297 return null; 1298 } 1299 1300 public static Node unwrapSingleArrayNode(Node n) { 1301 if (!(n instanceof ArrayNode)) return n; 1302 if (((ArrayNode) n).childNodes().size() > 1) return n; 1303 1304 return firstChild((ArrayNode) n); 1305 } 1306 1307 public Instruction visitReturnNode(ReturnNode iVisited) { 1308 print("return"); 1309 enterCall(); 1310 if (iVisited.getValueNode() != null) { 1311 print(' '); 1312 visitNode(unwrapSingleArrayNode(iVisited.getValueNode())); 1313 } 1314 leaveCall(); 1315 return null; 1316 } 1317 1318 public Instruction visitSClassNode(SClassNode iVisited) { 1319 print("class << "); 1320 config.getIndentor().indent(); 1321 visitNode(iVisited.getReceiverNode()); 1322 visitNode(iVisited.getBodyNode()); 1323 config.getIndentor().outdent(); 1324 printNewlineAndIndentation(); 1325 print("end"); 1326 return null; 1327 } 1328 1329 public Instruction visitSelfNode(SelfNode iVisited) { 1330 print("self"); 1331 return null; 1332 } 1333 1334 public Instruction visitSplatNode(SplatNode iVisited) { 1335 print("*"); 1336 visitNode(iVisited.getValue()); 1337 return null; 1338 } 1339 1340 private boolean stringIsHereDocument(StrNode n) { 1341 return sourceRangeEquals(getStartOffset(n) + 1, getStartOffset(n) + 3, "<<") || 1342 sourceRangeEquals(getStartOffset(n), getStartOffset(n) + 3, "<<-"); 1343 } 1344 1345 protected char getSeparatorForSym(Node n) { 1346 if (config.getSource().length() >= (getStartOffset(n)+1) && 1348 config.getSource().charAt(getStartOffset(n)+1) == '\'') { 1349 return '\''; 1350 } 1351 return '"'; 1352 } 1353 1354 protected char getSeparatorForStr(Node n) { 1355 if (config.getSource().length() >= getStartOffset(n) && 1356 config.getSource().charAt(getStartOffset(n)) == '\'') { 1357 return '\''; 1358 } 1359 return '"'; 1360 } 1361 1362 protected boolean inDRegxNode() { 1363 return false; 1364 } 1365 1366 public Instruction visitStrNode(StrNode iVisited) { 1367 if (stringIsHereDocument(iVisited)) { 1369 print("<<-EOF"); 1370 config.depositHereDocument(iVisited.getValue().toString()); 1371 return null; 1372 } 1373 1374 if(iVisited.getValue().equals("")) { 1375 if(config.getPrintQuotesInString().isTrue()) print("\"\""); 1376 1377 return null; 1378 } 1379 1380 if (config.getPrintQuotesInString().isTrue()) print(getSeparatorForStr(iVisited)); 1382 1383 if (inDRegxNode()) { 1384 print(iVisited.getValue().toString()); 1385 } else { 1386 Matcher matcher = Pattern.compile("([\\\\\\n\\f\\r\\t\\\"\\\'])").matcher(iVisited.getValue().toString()); 1387 1388 if (matcher.find()) { 1389 String unescChar = unescapeChar(matcher.group(1).charAt(0)); 1390 print(matcher.replaceAll("\\\\" + unescChar)); 1391 } else { 1392 print(iVisited.getValue().toString()); 1393 } 1394 } 1395 if (config.getPrintQuotesInString().isTrue()) print(getSeparatorForStr(iVisited)); 1396 1397 return null; 1398 } 1399 1400 public static String unescapeChar(char escapedChar) { 1401 switch (escapedChar) { 1402 case '\n': 1403 return "n"; 1404 case '\f': 1405 return "f"; 1406 case '\r': 1407 return "r"; 1408 case '\t': 1409 return "t"; 1410 case '\"': 1411 return "\""; 1412 case '\'': 1413 return "'"; 1414 case '\\': 1415 return "\\\\"; 1416 default: 1417 return null; 1418 } 1419 } 1420 1421 private boolean needsSuperNodeParentheses(SuperNode n) { 1422 return n.getArgsNode().childNodes().isEmpty() && 1423 config.getSource().charAt(getEndOffset(n)) == '('; 1424 } 1425 1426 public Instruction visitSuperNode(SuperNode iVisited) { 1427 print("super"); 1428 if (needsSuperNodeParentheses(iVisited)) print('('); 1429 1430 printCallArguments(iVisited.getArgsNode(), iVisited.getIterNode()); 1431 1432 if (needsSuperNodeParentheses(iVisited)) print(')'); 1433 1434 return null; 1435 } 1436 1437 public Instruction visitSValueNode(SValueNode iVisited) { 1438 visitNode(iVisited.getValue()); 1439 return null; 1440 } 1441 1442 public Instruction visitSymbolNode(SymbolNode iVisited) { 1443 print(':'); 1444 print(iVisited.getName()); 1445 return null; 1446 } 1447 1448 public Instruction visitToAryNode(ToAryNode iVisited) { 1449 visitNode(iVisited.getValue()); 1450 return null; 1451 } 1452 1453 public Instruction visitTrueNode(TrueNode iVisited) { 1454 print("true"); 1455 return null; 1456 } 1457 1458 public Instruction visitUndefNode(UndefNode iVisited) { 1459 print("undef "); 1460 print(iVisited.getName()); 1461 return null; 1462 } 1463 1464 public Instruction visitUntilNode(UntilNode iVisited) { 1465 print("until "); 1466 visitNode(iVisited.getConditionNode()); 1467 visitNodeInIndentation(iVisited.getBodyNode()); 1468 printNewlineAndIndentation(); 1469 print("end"); 1470 return null; 1471 } 1472 1473 public Instruction visitVAliasNode(VAliasNode iVisited) { 1474 print("alias "); 1475 print(iVisited.getNewName()); 1476 print(' '); 1477 print(iVisited.getOldName()); 1478 return null; 1479 } 1480 1481 public Instruction visitVCallNode(VCallNode iVisited) { 1482 print(iVisited.getName()); 1483 return null; 1484 } 1485 1486 public void visitNodeInIndentation(Node n) { 1487 config.getIndentor().indent(); 1488 visitNode(n); 1489 config.getIndentor().outdent(); 1490 } 1491 1492 public Instruction visitWhenNode(WhenNode iVisited) { 1493 printNewlineAndIndentation(); 1494 print("when "); 1495 enterCall(); 1496 visitAndPrintWithSeparator(iVisited.getExpressionNodes().childNodes().iterator()); 1497 leaveCall(); 1498 visitNodeInIndentation(iVisited.getBodyNode()); 1499 if ((iVisited.getNextCase() instanceof WhenNode || iVisited.getNextCase() == null)) { 1500 visitNode(iVisited.getNextCase()); 1501 } else { 1502 printNewlineAndIndentation(); 1503 print("else"); 1504 visitNodeInIndentation(iVisited.getNextCase()); 1505 } 1506 return null; 1507 } 1508 1509 protected void visitNewlineInParentheses(Node n) { 1510 if (n instanceof NewlineNode) { 1511 if (((NewlineNode) n).getNextNode() instanceof SplatNode) { 1512 print('['); 1513 visitNode(((NewlineNode) n).getNextNode()); 1514 print(']'); 1515 } else { 1516 print('('); 1517 visitNode(((NewlineNode) n).getNextNode()); 1518 print(')'); 1519 } 1520 } else { 1521 visitNode(n); 1522 } 1523 } 1524 1525 private void printWhileStatement(WhileNode iVisited) { 1526 print("while "); 1527 1528 if (isAssignment(iVisited.getConditionNode())) enterCall(); 1529 1530 visitNewlineInParentheses(iVisited.getConditionNode()); 1531 1532 if (isAssignment(iVisited.getConditionNode())) leaveCall(); 1533 1534 visitNodeInIndentation(iVisited.getBodyNode()); 1535 1536 printNewlineAndIndentation(); 1537 print("end"); 1538 } 1539 1540 private void printDoWhileStatement(WhileNode iVisited) { 1541 print("begin"); 1542 visitNodeInIndentation(iVisited.getBodyNode()); 1543 printNewlineAndIndentation(); 1544 print("end while "); 1545 visitNode(iVisited.getConditionNode()); 1546 } 1547 1548 public Instruction visitWhileNode(WhileNode iVisited) { 1549 if (iVisited.evaluateAtStart()) { 1550 printWhileStatement(iVisited); 1551 } else { 1552 printDoWhileStatement(iVisited); 1553 } 1554 return null; 1555 } 1556 1557 public Instruction visitXStrNode(XStrNode iVisited) { 1558 print('`'); 1559 print(iVisited.getValue().toString()); 1560 print('`'); 1561 return null; 1562 } 1563 1564 public Instruction visitYieldNode(YieldNode iVisited) { 1565 print("yield"); 1566 1567 if (iVisited.getArgsNode() != null) { 1568 print(needsParentheses(iVisited.getArgsNode()) ? '(' : ' '); 1569 1570 enterCall(); 1571 1572 if (iVisited.getArgsNode() instanceof ArrayNode) { 1573 visitAndPrintWithSeparator(iVisited.getArgsNode().childNodes().iterator()); 1574 } else { 1575 visitNode(iVisited.getArgsNode()); 1576 } 1577 1578 leaveCall(); 1579 1580 if (needsParentheses(iVisited.getArgsNode())) print(')'); 1581 } 1582 return null; 1583 } 1584 1585 public Instruction visitZArrayNode(ZArrayNode iVisited) { 1586 print("[]"); 1587 return null; 1588 } 1589 1590 public Instruction visitZSuperNode(ZSuperNode iVisited) { 1591 print("super"); 1592 return null; 1593 } 1594 1595 private static int getStartLine(Node n) { 1596 return n.getPosition().getStartLine(); 1597 } 1598 1599 private static int getStartOffset(Node n) { 1600 return n.getPosition().getStartOffset(); 1601 } 1602 1603 private static int getEndLine(Node n) { 1604 return n.getPosition().getEndLine(); 1605 } 1606 1607 protected static int getEndOffset(Node n) { 1608 return n.getPosition().getEndOffset(); 1609 } 1610 1611 public ReWriterContext getConfig() { 1612 return config; 1613 } 1614 1615 public static String createCodeFromNode(Node node, String document){ 1616 return createCodeFromNode(node, document, new DefaultFormatHelper()); 1617 } 1618 1619 public static String createCodeFromNode(Node node, String document, FormatHelper helper){ 1620 StringWriter writer = new StringWriter (); 1621 ReWriterContext ctx = new ReWriterContext(writer, document, helper); 1622 ReWriteVisitor rewriter = new ReWriteVisitor(ctx); 1623 rewriter.visitNode(node); 1624 return writer.toString(); 1625 } 1626 1627 public Instruction visitArgsPushNode(ArgsPushNode node) { 1628 assert false : "Unhandled node"; 1629 return null; 1630 } 1631 1632 public Instruction visitAttrAssignNode(AttrAssignNode iVisited) { 1633 if (iVisited.getName().equals("[]=")) return printIndexAssignment(iVisited); 1634 1635 if (iVisited.getName().endsWith("=")) { 1636 visitNode(iVisited.getReceiverNode()); 1637 print('.'); 1638 1639 printNameWithoutEqualSign(iVisited); 1640 printAssignmentOperator(); 1641 if (iVisited.getArgsNode() != null) { 1642 visitAndPrintWithSeparator(iVisited.getArgsNode().childNodes().iterator()); 1643 } 1644 } else { 1645 assert false : "Unhandled AttrAssignNode"; 1646 } 1647 1648 return null; 1649 } 1650 1651 private void printNameWithoutEqualSign(INameNode iVisited) { 1652 print(iVisited.getName().substring(0, iVisited.getName().length() - 1)); 1653 } 1654 1655 public Instruction visitRootNode(RootNode iVisited) { 1656 config.getLocalVariables().addLocalVariable(iVisited.getStaticScope()); 1657 visitNode(iVisited.getBodyNode()); 1658 if (config.hasHereDocument()) config.fetchHereDocument().print(); 1659 1660 return null; 1661 } 1662} 1663 | Popular Tags |