KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jruby > ast > visitor > rewriter > ReWriteVisitor


1 /***** BEGIN LICENSE BLOCK *****
2  * Version: CPL 1.0/GPL 2.0/LGPL 2.1
3  *
4  * The contents of this file are subject to the Common Public
5  * License Version 1.0 (the "License"); you may not use this file
6  * except in compliance with the License. You may obtain a copy of
7  * the License at http://www.eclipse.org/legal/cpl-v10.html
8  *
9  * Software distributed under the License is distributed on an "AS
10  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
11  * implied. See the License for the specific language governing
12  * rights and limitations under the License.
13  *
14  * Copyright (C) 2006 Mirko Stocker <me@misto.ch>
15  *
16  * Alternatively, the contents of this file may be used under the terms of
17  * either of the GNU General Public License Version 2 or later (the "GPL"),
18  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
19  * in which case the provisions of the GPL or the LGPL are applicable instead
20  * of those above. If you wish to allow use of your version of this file only
21  * under the terms of either the GPL or the LGPL, and not to allow others to
22  * use your version of this file under the terms of the CPL, indicate your
23  * decision by deleting the provisions above and replace them with the notice
24  * and other provisions required by the GPL or the LGPL. If you do not delete
25  * the provisions above, a recipient may use your version of this file under
26  * the terms of any one of the CPL, the GPL or the LGPL.
27  ***** END LICENSE BLOCK *****/

28
29 package org.jruby.ast.visitor.rewriter;
30
31 import java.io.OutputStream JavaDoc;
32 import java.io.PrintWriter JavaDoc;
33 import java.io.StringWriter JavaDoc;
34 import java.io.Writer JavaDoc;
35 import java.math.BigInteger JavaDoc;
36 import java.util.ArrayList JavaDoc;
37 import java.util.Iterator JavaDoc;
38 import java.util.regex.Matcher JavaDoc;
39 import java.util.regex.Pattern JavaDoc;
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 /**
51  * Visits each node and outputs the corresponding Ruby sourcecode for the nodes.
52  *
53  * @author Mirko Stocker
54  *
55  */

56 public class ReWriteVisitor implements NodeVisitor {
57     
58     protected final ReWriterContext config;
59     protected final ReWriterFactory factory;
60     
61     public ReWriteVisitor(Writer JavaDoc out, String JavaDoc source) {
62         this(new ReWriterContext(new PrintWriter JavaDoc(out), source, new DefaultFormatHelper()));
63     }
64
65     public ReWriteVisitor(OutputStream JavaDoc out, String JavaDoc source) {
66         this(new ReWriterContext(new PrintWriter JavaDoc(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 JavaDoc 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 JavaDoc 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 JavaDoc 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 JavaDoc 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 JavaDoc iterator) {
167         while (iterator.hasNext()) {
168             visitNode((Node) iterator.next());
169         }
170     }
171
172     private void visitIterAndSkipFirst(Iterator JavaDoc 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 JavaDoc 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 JavaDoc compare) {
264         return (stop <= config.getSource().length() && sourceSubStringEquals(start, stop - start, compare));
265     }
266     
267     private boolean sourceRangeContains(ISourcePosition pos, String JavaDoc 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 JavaDoc collectAllArguments(ArgsNode iVisited) {
288         ArrayList JavaDoc arguments = new ArrayList JavaDoc();
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 JavaDoc 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 JavaDoc 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 JavaDoc 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 JavaDoc 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 JavaDoc writer = new StringWriter JavaDoc();
605         PrintWriter JavaDoc oldOut = config.getOutput();
606         config.setOutput(new PrintWriter JavaDoc(writer));
607
608         for (Iterator JavaDoc 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 JavaDoc 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 JavaDoc 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 JavaDoc 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 JavaDoc 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 JavaDoc 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     /**
868      * Elsif-conditions in the AST are represented by multiple nested if / else
869      * combinations. This method takes a node and checks if the node is an
870      * elsif-statement or a normal else node.
871      *
872      * @param iVisited
873      * @return Returns the last ElseNode or null.
874      */

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 JavaDoc 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         // We have to skip a possible Newline here:
930
visitNewlineInParentheses(iVisited.getCondition());
931         
932         if (isAssignment(iVisited.getCondition())) leaveCall();
933
934         config.getIndentor().indent();
935         // we have to check this to generate valid code for this style: "return
936
// if true", because there is no newline
937
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 JavaDoc 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        // this node is never used in the parser, only here:
1158
// org.jruby/src/org/jruby/Main.java
1159
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        // this node contains nothing but an empty list, so we don't have to
1178
// process anything
1179
return null;
1180    }
1181
1182    public Instruction visitRedoNode(RedoNode iVisited) {
1183        print("redo");
1184        return null;
1185    }
1186
1187    private String JavaDoc getFirstRegexpEnclosure(Node n) {
1188        return isSpecialRegexNotation(n) ? "%r(" : "/";
1189    }
1190
1191    private String JavaDoc 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 the exception is assigned to a variable, we have to skip the first
1250
// node in the body
1251
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        // ENEBO: I added one since a sym will start with ':'...This seems like an incomplete assumption
1347
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        // look for a here-document:
1368
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        // don't print quotes if we are a subpart of an other here-document
1381
if (config.getPrintQuotesInString().isTrue()) print(getSeparatorForStr(iVisited));
1382
1383        if (inDRegxNode()) {
1384            print(iVisited.getValue().toString());
1385        } else {
1386            Matcher JavaDoc matcher = Pattern.compile("([\\\\\\n\\f\\r\\t\\\"\\\'])").matcher(iVisited.getValue().toString());
1387
1388            if (matcher.find()) {
1389                String JavaDoc 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 JavaDoc 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 JavaDoc createCodeFromNode(Node node, String JavaDoc document){
1616        return createCodeFromNode(node, document, new DefaultFormatHelper());
1617    }
1618    
1619    public static String JavaDoc createCodeFromNode(Node node, String JavaDoc document, FormatHelper helper){
1620        StringWriter JavaDoc writer = new StringWriter JavaDoc();
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