Package org.jruby.ast.visitor.rewriter

Source Code of org.jruby.ast.visitor.rewriter.ReWriteVisitor

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

package org.jruby.ast.visitor.rewriter;

import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.jruby.ast.*;
import org.jruby.ast.types.INameNode;
import org.jruby.ast.visitor.NodeVisitor;
import org.jruby.ast.visitor.rewriter.utils.Operators;
import org.jruby.ast.visitor.rewriter.utils.ReWriterContext;
import org.jruby.evaluator.Instruction;
import org.jruby.lexer.yacc.ISourcePosition;
import org.jruby.parser.StaticScope;

/**
* Visits each node and outputs the corresponding Ruby sourcecode for the nodes.
*
* @author Mirko Stocker
*
*/
public class ReWriteVisitor implements NodeVisitor {
 
  protected final ReWriterContext config;
  protected final ReWriterFactory factory;
 
  public ReWriteVisitor(Writer out, String source) {
    this(new ReWriterContext(new PrintWriter(out), source, new DefaultFormatHelper()));
  }

  public ReWriteVisitor(OutputStream out, String source) {
    this(new ReWriterContext(new PrintWriter(out, true), source, new DefaultFormatHelper()));
  }

  public ReWriteVisitor(ReWriterContext config) {
    this.config = config;
    factory = new ReWriterFactory(config);
  }

  public void flushStream() {
    config.getOutput().flush();
  }
 
  protected void print(String s) {
    config.getOutput().print(s);
  }
 
  protected void print(char c) {
    config.getOutput().print(c);
  }
 
  protected void print(BigInteger i) {
    config.getOutput().print(i);
  }
 
  protected void print(int i) {
    config.getOutput().print(i);
  }
 
  protected void print(long l) {
    config.getOutput().print(l);
  }
 
  protected void print(double d) {
    config.getOutput().print(d);
  }
 
  private void enterCall() {
    config.getCallDepth().enterCall();
  }

  private void leaveCall() {
    config.getCallDepth().leaveCall();
  }

  private boolean inCall() {
    return config.getCallDepth().inCall();
  }

  protected void printNewlineAndIndentation() {
    if (config.hasHereDocument()) config.fetchHereDocument().print();

    print(config.getFormatHelper().getLineDelimiter());
    config.getIndentor().printIndentation(config.getOutput());
  }

  private static boolean isReceiverACallNode(CallNode n) {
    return (n.getReceiverNode() instanceof CallNode || n.getReceiverNode() instanceof FCallNode);
  }

    private void printCommentsBefore(Node iVisited) {

        for (CommentNode n: iVisited.getComments()) {
      if (getStartLine(n) < getStartLine(iVisited)) {
        visitNode(n);
        print(n.getContent());
                printNewlineAndIndentation();
      }
    }
  }

  protected boolean printCommentsAfter(Node iVisited) {
    boolean hasComment = false;
       
        for (CommentNode n: iVisited.getComments()) {
      if(getStartLine(n) >= getEndLine(iVisited)) {
        print(' ');
        visitNode(n);
                print(n.getContent());
        hasComment = true;
      }
    }
       
    return hasComment;
  }
 
  public void visitNode(Node iVisited) {
            if (iVisited == null || iVisited.isInvisible()) return;
       
        printCommentsBefore(iVisited);

        if (iVisited instanceof ArgumentNode) {
            print(((ArgumentNode) iVisited).getName());
        } else {
            iVisited.accept(this);
        }

        printCommentsAfter(iVisited);
        config.setLastPosition(iVisited.getPosition());
  }

  public void visitIter(Iterator iterator) {
    while (iterator.hasNext()) {
      visitNode((Node) iterator.next());
    }
  }

  private void visitIterAndSkipFirst(Iterator iterator) {
    iterator.next();
    visitIter(iterator);
  }

  private static boolean isStartOnNewLine(Node first, Node second) {
    if (first == null || second == null) return false;
       
    return (getStartLine(first) < getStartLine(second));
  }

  private boolean needsParentheses(Node n) {
        return (n != null && (n.childNodes().size() > 1 || inCall() || firstChild(n) instanceof HashNode)
        || firstChild(n) instanceof NewlineNode || firstChild(n) instanceof IfNode);
  }

  private void printCallArguments(Node argsNode, Node iterNode) {
        if (argsNode != null && argsNode.childNodes().size() < 1 && iterNode == null) return;
                   
        if (argsNode != null && argsNode.childNodes().size() == 1 &&
                firstChild(argsNode) instanceof HashNode && iterNode == null) {
      HashNode hashNode = (HashNode) firstChild(argsNode);
      if(hashNode.getListNode().childNodes().size() < 1) {
        print("({})");
      } else {
        print(' ');
        printHashNodeContent(hashNode);
      }
      return;
    }

    boolean paranthesesPrinted = needsParentheses(argsNode)
            || (argsNode == null && iterNode != null && iterNode instanceof BlockPassNode)
            || (argsNode != null && argsNode.childNodes().size() > 0 && iterNode != null);
       
    if (paranthesesPrinted) {
      print('(');
        } else if (argsNode != null) {
      print(config.getFormatHelper().beforeCallArguments());
        }

    if (firstChild(argsNode) instanceof NewlineNode) {
      config.setSkipNextNewline(true);
        }

    enterCall();

    if (argsNode instanceof SplatNode) {
      visitNode(argsNode);
        } else if (argsNode != null) {
      visitAndPrintWithSeparator(argsNode.childNodes().iterator());
        }

        if (iterNode instanceof BlockPassNode) {
            if (argsNode != null) print(config.getFormatHelper().getListSeparator());
           
            print('&');
            visitNode(((BlockPassNode) iterNode).getBodyNode());
        }

    if (paranthesesPrinted) {
      print(')');
        } else {
      print(config.getFormatHelper().afterCallArguments());
        }

    leaveCall();
  }

  public void visitAndPrintWithSeparator(Iterator<Node> it) {
    while (it.hasNext()) {
      Node n = it.next();
      factory.createIgnoreCommentsReWriteVisitor().visitNode(n);
      if (it.hasNext())
        print(config.getFormatHelper().getListSeparator());
      if(n.hasComments()) {
        factory.createReWriteVisitor().visitIter(n.getComments().iterator());
        printNewlineAndIndentation();
      }
    }
  }

  public Instruction visitAliasNode(AliasNode iVisited) {
    print("alias ");
    print(iVisited.getNewName());
    print(' ');
    print(iVisited.getOldName());
    printCommentsAtEnd(iVisited);
    return null;
  }

  private boolean sourceRangeEquals(int start, int stop, String compare) {
    return (stop <= config.getSource().length() && sourceSubStringEquals(start, stop - start, compare));
  }
 
  private boolean sourceRangeContains(ISourcePosition pos, String searched) {
    return pos.getStartOffset() < config.getSource().length()
      && pos.getEndOffset() < config.getSource().length() + 1
      && config.getSource().substring(pos.getStartOffset(), pos.getEndOffset()).indexOf(searched) > -1;
  }
  public Instruction visitAndNode(AndNode iVisited) {
    enterCall();
    visitNode(iVisited.getFirstNode());
       
    if (sourceRangeContains(iVisited.getPosition(), "&&")) {
      print(" && ");
        } else {
      print(" and ");
        }
    visitNode(iVisited.getSecondNode());
    leaveCall();
    return null;
  }


  private ArrayList<Node> collectAllArguments(ArgsNode iVisited) {
    ArrayList<Node> arguments = new ArrayList<Node>();
       
    if (iVisited.getArgs() != null) arguments.addAll(iVisited.getArgs().childNodes());
       
    if (iVisited.getOptArgs() != null) arguments.addAll(iVisited.getOptArgs().childNodes());
       
    if (iVisited.getRestArgNode() != null) {
      arguments.add(new ConstNode(iVisited.getRestArgNode().getPosition(), '*' + iVisited.getRestArgNode().getName()));
          }
       
    if (iVisited.getBlockArgNode() != null) arguments.add(iVisited.getBlockArgNode());
       
    return arguments;
  }
 
  private boolean hasNodeCommentsAtEnd(Node n) {
      for (Node comment: n.getComments()) {
      if (getStartLine(comment) == getStartLine(n)) return true;
    }
       
    return false;
  }
 
  private void printCommentsInArgs(Node n, boolean hasNext) {
    if (hasNodeCommentsAtEnd(n) && hasNext) print(",");
       
    if (printCommentsAfter(n) && hasNext) {
      printNewlineAndIndentation();
    } else if (hasNext) {
      print(config.getFormatHelper().getListSeparator());
        }
  }
 
  public Instruction visitArgsNode(ArgsNode iVisited) {

    for (Iterator<Node> it = collectAllArguments(iVisited).iterator(); it.hasNext(); ) {
      Node n = it.next();
           
      if (n instanceof ArgumentNode) {
        print(((ArgumentNode) n).getName());
        printCommentsInArgs(n, it.hasNext());
      } else {
        visitNode(n);
        if (it.hasNext()) print(config.getFormatHelper().getListSeparator());
      }
           
      if (!it.hasNext()) print(config.getFormatHelper().afterMethodArguments());
    }
     
    return null;
  }

  public Instruction visitArgsCatNode(ArgsCatNode iVisited) {
    print("[");
    visitAndPrintWithSeparator(iVisited.getFirstNode().childNodes().iterator());
    print(config.getFormatHelper().getListSeparator());
    print("*");
    visitNode(iVisited.getSecondNode());
    print("]");
    return null;
  }

  public Instruction visitArrayNode(ArrayNode iVisited) {
    print('[');
    enterCall();
    visitAndPrintWithSeparator(iVisited.childNodes().iterator());
    leaveCall();
    print(']');
    return null;
  }

  public Instruction visitBackRefNode(BackRefNode iVisited) {
    print('$');
    print(iVisited.getType());
    return null;
  }

  public Instruction visitBeginNode(BeginNode iVisited) {
    print("begin");
    visitNodeInIndentation(iVisited.getBodyNode());
    printNewlineAndIndentation();
    print("end");
    return null;
  }

  public Instruction visitBignumNode(BignumNode iVisited) {
    print(iVisited.getValue());
    return null;
  }

  public Instruction visitBlockArgNode(BlockArgNode iVisited) {
    print('&');
    print(iVisited.getName());
    return null;
  }

  public Instruction visitBlockNode(BlockNode iVisited) {
    visitIter(iVisited.childNodes().iterator());
    return null;
  }

  public static int getLocalVarIndex(Node n) {
    return n instanceof LocalVarNode ? ((LocalVarNode) n).getIndex() : -1;
  }

  public Instruction visitBlockPassNode(BlockPassNode iVisited) {
      visitNode(iVisited.getBodyNode());
    return null;
  }

  public Instruction visitBreakNode(BreakNode iVisited) {
    print("break");
    return null;
  }

  public Instruction visitConstDeclNode(ConstDeclNode iVisited) {
    printAsgnNode(iVisited);
    return null;
  }

  public Instruction visitClassVarAsgnNode(ClassVarAsgnNode iVisited) {
    printAsgnNode(iVisited);
    return null;
  }

  public Instruction visitClassVarDeclNode(ClassVarDeclNode iVisited) {
    printAsgnNode(iVisited);
    return null;
  }

  public Instruction visitClassVarNode(ClassVarNode iVisited) {
    print(iVisited.getName());
    return null;
  }

  private boolean isNumericNode(Node n) {
    return (n != null && (n instanceof FixnumNode || n instanceof BignumNode));
  }

  private boolean isNameAnOperator(String name) {
    return Operators.contain(name);
  }

  private boolean printSpaceInsteadOfDot(CallNode n) {
    return (isNameAnOperator(n.getName()) && !(n.getArgsNode().childNodes().size() > 1));
  }
 
  protected void printAssignmentOperator(){
    print(config.getFormatHelper().beforeAssignment());
    print("=");
    print(config.getFormatHelper().afterAssignment());
  }

  private Instruction printIndexAssignment(AttrAssignNode iVisited) {
    enterCall();
    visitNode(iVisited.getReceiverNode());
    leaveCall();
    print('[');
    visitNode(firstChild(iVisited.getArgsNode()));
    print("]");
    printAssignmentOperator();
    if (iVisited.getArgsNode().childNodes().size() > 1)
      visitNode((Node) iVisited.getArgsNode().childNodes().get(1));
    return null;
  }

  private Instruction printIndexAccess(CallNode visited) {
    enterCall();
    visitNode(visited.getReceiverNode());
    leaveCall();
    print('[');
    if (visited.getArgsNode() != null) {
      visitAndPrintWithSeparator(visited.getArgsNode().childNodes().iterator());
        }
    print("]");
    return null;
  }
 
  private Instruction printNegativNumericNode(CallNode visited) {
    print('-');
    visitNode(visited.getReceiverNode());
    return null;
  }
 
  private boolean isNegativeNumericNode(CallNode visited) {
    return isNumericNode(visited.getReceiverNode()) && visited.getName().equals("-@");
  }
 
  private void printCallReceiverNode(CallNode iVisited) {
    if (iVisited.getReceiverNode() instanceof HashNode) print('(');

    if (isReceiverACallNode(iVisited) && !printSpaceInsteadOfDot(iVisited)) {
      enterCall();
      visitNewlineInParentheses(iVisited.getReceiverNode());
      leaveCall();
    } else {
      visitNewlineInParentheses(iVisited.getReceiverNode());
        }

    if (iVisited.getReceiverNode() instanceof HashNode) print(')');
  }
 
  protected boolean inMultipleAssignment() {
    return false;
  }

  public Instruction visitCallNode(CallNode iVisited) {
    if (isNegativeNumericNode(iVisited)) return printNegativNumericNode(iVisited);
       
    if (iVisited.getName().equals("[]")) return printIndexAccess(iVisited);
    
    printCallReceiverNode(iVisited);

    print(printSpaceInsteadOfDot(iVisited) ? ' ' : '.');

    if (inMultipleAssignment() && iVisited.getName().endsWith("=")) {
      print(iVisited.getName().substring(0, iVisited.getName().length() - 1));
        } else {
      print(iVisited.getName());
        }

    if (isNameAnOperator(iVisited.getName())) {
      if (firstChild(iVisited.getArgsNode()) instanceof NewlineNode) print(' ');
           
      config.getCallDepth().disableCallDepth();
    }
    printCallArguments(iVisited.getArgsNode(), iVisited.getIterNode());

    if (isNameAnOperator(iVisited.getName())) config.getCallDepth().enableCallDepth();
        if (!(iVisited.getIterNode() instanceof BlockPassNode)) visitNode(iVisited.getIterNode());

    return null;
  }

  public Instruction visitCaseNode(CaseNode iVisited) {
    print("case ");
    visitNode(iVisited.getCaseNode());
    visitNode(iVisited.getFirstWhenNode());
    printNewlineAndIndentation();
    print("end");
    return null;
  }
       
  private boolean printCommentsIn(Node iVisited) {
    boolean hadComment = false;
    for (CommentNode n: iVisited.getComments()) {
      if(getStartLine(n) > getStartLine(iVisited) && getEndLine(n) < getEndLine(iVisited)) {
        hadComment = true;
        visitNode(n);
                print(n.getContent());
        printNewlineAndIndentation();
      }
    }
   
    return hadComment;
  }

  public Instruction visitClassNode(ClassNode iVisited) {

    print("class ");
    visitNode(iVisited.getCPath());
    if (iVisited.getSuperNode() != null) {
      print(" < ");
      visitNode(iVisited.getSuperNode());
    }

    new ClassBodyWriter(this, iVisited.getBodyNode()).write();
   
    printNewlineAndIndentation();   
    printCommentsIn(iVisited);
   
    print("end");
    return null;
  }

  public Instruction visitColon2Node(Colon2Node iVisited) {
    if (iVisited.getLeftNode() != null) {
      visitNode(iVisited.getLeftNode());
      print("::");
    }
    print(iVisited.getName());
    return null;
  }

  public Instruction visitColon3Node(Colon3Node iVisited) {
    print("::");
    print(iVisited.getName());
    return null;
  }

  public Instruction visitConstNode(ConstNode iVisited) {
    print(iVisited.getName());
    return null;
  }

  public Instruction visitDAsgnNode(DAsgnNode iVisited) {
    printAsgnNode(iVisited);
    return null;
  }

  public Instruction visitDRegxNode(DRegexpNode iVisited) {
    config.getPrintQuotesInString().set(false);
    print(getFirstRegexpEnclosure(iVisited));
    factory.createDRegxReWriteVisitor().visitIter(iVisited.childNodes().iterator());
    print(getSecondRegexpEnclosure(iVisited));
    printRegexpOptions(iVisited.getOptions());
    config.getPrintQuotesInString().revert();
    return null;
  }
 
  private Instruction createHereDocument(DStrNode iVisited) {
    config.getPrintQuotesInString().set(false);
    print("<<-EOF");
    StringWriter writer = new StringWriter();
    PrintWriter oldOut = config.getOutput();
    config.setOutput(new PrintWriter(writer));

    for (Iterator it = iVisited.childNodes().iterator(); it.hasNext(); ) {
      factory.createHereDocReWriteVisitor().visitNode((Node) it.next());
           
      if (it.hasNext()) config.setSkipNextNewline(true);
    }
       
    config.setOutput(oldOut);
    config.depositHereDocument(writer.getBuffer().toString());
    config.getPrintQuotesInString().revert();

    return null;
  }

  public Instruction visitDStrNode(DStrNode iVisited) {

    if (firstChild(iVisited) instanceof StrNode && stringIsHereDocument((StrNode) firstChild(iVisited))) {
      return createHereDocument(iVisited);
    }

    if (config.getPrintQuotesInString().isTrue()) print(getSeparatorForStr(iVisited));
       
    config.getPrintQuotesInString().set(false);
    leaveCall();
    for (Node child: iVisited.childNodes()) {
            visitNode(child);
    }
    enterCall();
    config.getPrintQuotesInString().revert();
       
    if (config.getPrintQuotesInString().isTrue()) print(getSeparatorForStr(iVisited));
       
    return null;
  }

  public Instruction visitDSymbolNode(DSymbolNode iVisited) {
    print(':');
        if (config.getPrintQuotesInString().isTrue()) print(getSeparatorForSym(iVisited));
       
        config.getPrintQuotesInString().set(false);
        leaveCall();
        for (Node child: iVisited.childNodes()) {
            visitNode(child);
        }       
        enterCall();
        config.getPrintQuotesInString().revert();
       
        if (config.getPrintQuotesInString().isTrue()) print(getSeparatorForSym(iVisited));
    return null;
  }

  public Instruction visitDVarNode(DVarNode iVisited) {
    print(iVisited.getName());
    return null;
  }

  public Instruction visitDXStrNode(DXStrNode iVisited) {
    config.getPrintQuotesInString().set(false);
    print("%x{");
    visitIter(iVisited.childNodes().iterator());
    print('}');
    config.getPrintQuotesInString().revert();
    return null;
  }

  public Instruction visitDefinedNode(DefinedNode iVisited) {
    print("defined? ");
    enterCall();
    visitNode(iVisited.getExpressionNode());
    leaveCall();
    return null;
  }

  private boolean hasArguments(Node n) {
    if (n instanceof ArgsNode) {
      ArgsNode args = (ArgsNode) n;
      return (args.getArgs() != null || args.getOptArgs() != null
          || args.getBlockArgNode() != null || args.getRestArgNode() != null);
    } else if (n instanceof ArrayNode && n.childNodes().isEmpty()) {
      return false;
    }
    return true;
  }
       
  protected void printCommentsAtEnd(Node n) {
    for (CommentNode comment: n.getComments()) {
      if (getStartLine(n) == getStartLine(comment)) {
        print(' ');
        visitNode(comment);
                print(comment.getContent());
      }
    }
  }
 
  private void printDefNode(Node parent, String name, Node args, StaticScope scope, Node bodyNode) {
    print(name);
    config.getLocalVariables().addLocalVariable(scope);

    if (hasArguments(args)) {
        print(config.getFormatHelper().beforeMethodArguments());
            visitNode(args);
    }
        printCommentsAtEnd(parent);
       
    visitNode(bodyNode);
    config.getIndentor().outdent();
    printNewlineAndIndentation();
    printCommentsIn(parent);
    print("end");
  }

  public Instruction visitDefnNode(DefnNode iVisited) {
    config.getIndentor().indent();
    print("def ");
    printDefNode(iVisited, iVisited.getName(), iVisited.getArgsNode(), iVisited.getScope(), iVisited.getBodyNode());
    return null;
  }

  public Instruction visitDefsNode(DefsNode iVisited) {
    config.getIndentor().indent();
    print("def ");
    visitNode(iVisited.getReceiverNode());
    print('.');
    printDefNode(iVisited, iVisited.getName(), iVisited.getArgsNode(), iVisited.getScope(), iVisited.getBodyNode());
    return null;
  }

  public Instruction visitDotNode(DotNode iVisited) {
    enterCall();
    visitNode(iVisited.getBeginNode());
    print("..");
    if (iVisited.isExclusive()) print('.');
    visitNode(iVisited.getEndNode());
    leaveCall();
    return null;
  }

  public Instruction visitEnsureNode(EnsureNode iVisited) {
    visitNode(iVisited.getBodyNode());
    config.getIndentor().outdent();
    printNewlineAndIndentation();
    print("ensure");
    visitNodeInIndentation(iVisited.getEnsureNode());
    config.getIndentor().indent();
    return null;
  }

  public Instruction visitEvStrNode(EvStrNode iVisited) {
    print('#');
    if (!(iVisited.getBody() instanceof NthRefNode)) print('{');
    config.getPrintQuotesInString().set(true);
    visitNode(unwrapNewlineNode(iVisited.getBody()));
    config.getPrintQuotesInString().revert();
    if (!(iVisited.getBody() instanceof NthRefNode)) print('}');
    return null;
  }
 
  private Node unwrapNewlineNode(Node node) {
    return node instanceof NewlineNode ? ((NewlineNode) node).getNextNode() : node;
  }

  public Instruction visitFCallNode(FCallNode iVisited) {
    print(iVisited.getName());
       
        if (iVisited.getIterNode() != null) config.getCallDepth().enterCall();
       
    printCallArguments(iVisited.getArgsNode(), iVisited.getIterNode());
       
        if (iVisited.getIterNode() != null) config.getCallDepth().leaveCall();

        if (!(iVisited.getIterNode() instanceof BlockPassNode)) visitNode(iVisited.getIterNode());

    return null;
  }

  public Instruction visitFalseNode(FalseNode iVisited) {
    print("false");
    return null;
  }

  public Instruction visitFixnumNode(FixnumNode iVisited) {
    print(iVisited.getValue());
    return null;
  }

  public Instruction visitFlipNode(FlipNode iVisited) {
    enterCall();
    visitNode(iVisited.getBeginNode());
    print(" ..");
    if (iVisited.isExclusive())  print('.');
    print(' ');
    visitNode(iVisited.getEndNode());
    leaveCall();
    return null;
  }

  public Instruction visitFloatNode(FloatNode iVisited) {
    print(iVisited.getValue());
    return null;
  }

  public Instruction visitForNode(ForNode iVisited) {
    print("for ");
    visitNode(iVisited.getVarNode());
    print(" in ");
    visitNode(iVisited.getIterNode());
    visitNodeInIndentation(iVisited.getBodyNode());
    printNewlineAndIndentation();
    print("end");
    return null;
  }

  public Instruction visitGlobalAsgnNode(GlobalAsgnNode iVisited) {
    printAsgnNode(iVisited);
    return null;
  }

  public Instruction visitGlobalVarNode(GlobalVarNode iVisited) {
    print(iVisited.getName());
    return null;
  }

  private void printHashNodeContent(HashNode iVisited) {
    print(config.getFormatHelper().beforeHashContent());
    if (iVisited.getListNode() != null) {
      for (Iterator it = iVisited.getListNode().childNodes().iterator(); it.hasNext(); ) {
        visitNode((Node) it.next());
        print(config.getFormatHelper().hashAssignment());
        visitNode((Node) it.next());
               
        if (it.hasNext()) print(config.getFormatHelper().getListSeparator());
      }
    }
    print(config.getFormatHelper().afterHashContent());
  }

  public Instruction visitHashNode(HashNode iVisited) {
    print('{');
    printHashNodeContent(iVisited);
    print('}');
    return null;
  }

  private void printAsgnNode(AssignableNode n) {
    print(((INameNode) n).getName());
    if (n.getValueNode() == null || n.getValueNode().isInvisible()) return;
    printAssignmentOperator();
    visitNewlineInParentheses(n.getValueNode());
  }

  public Instruction visitInstAsgnNode(InstAsgnNode iVisited) {
    printAsgnNode(iVisited);
    return null;
  }

  public Instruction visitInstVarNode(InstVarNode iVisited) {
    print(iVisited.getName());
    return null;
  }

  /**
   * Elsif-conditions in the AST are represented by multiple nested if / else
   * combinations. This method takes a node and checks if the node is an
   * elsif-statement or a normal else node.
   *
   * @param iVisited
   * @return Returns the last ElseNode or null.
   */
  private Node printElsIfNodes(Node iVisited) {
    if (iVisited != null && iVisited instanceof IfNode) {
      IfNode n = (IfNode) iVisited;
      printNewlineAndIndentation();
      print("elsif ");
      visitNode(n.getCondition());
      visitNodeInIndentation(n.getThenBody());
      return printElsIfNodes(n.getElseBody());
    }
     
        return iVisited != null ? iVisited : null;
  }

  private Instruction printShortIfStatement(IfNode n) {
    if (n.getThenBody() == null) {
      visitNode(n.getElseBody());
      print(" unless ");
      visitNode(n.getCondition());
    } else {
      enterCall();
      factory.createShortIfNodeReWriteVisitor().visitNode(n.getCondition());
      print(" ? ");
      factory.createShortIfNodeReWriteVisitor().visitNode(n.getThenBody());
      print(" : ");
      factory.createShortIfNodeReWriteVisitor().visitNewlineInParentheses(n.getElseBody());
      leaveCall();
    }
    return null;
  }

  private boolean isAssignment(Node n) {
    return (n instanceof DAsgnNode || n instanceof GlobalAsgnNode
        || n instanceof InstAsgnNode || n instanceof LocalAsgnNode || n instanceof ClassVarAsgnNode);
  }

  private boolean sourceSubStringEquals(int offset, int length, String str) {
    return config.getSource().length() >= offset + length
      && config.getSource().substring(offset, offset + length).equals(str);
  }
 
  private boolean isShortIfStatement(IfNode iVisited) {
    return (isOnSingleLine(iVisited.getCondition(), iVisited.getElseBody())
        && !(iVisited.getElseBody() instanceof IfNode)
        && !sourceSubStringEquals(getStartOffset(iVisited), 2, "if"));
  }

  public Instruction visitIfNode(IfNode iVisited) {

    if (isShortIfStatement(iVisited)) return printShortIfStatement(iVisited);

    print("if ");

    if (isAssignment(iVisited.getCondition())) enterCall();

    // We have to skip a possible Newline here:
    visitNewlineInParentheses(iVisited.getCondition());
       
    if (isAssignment(iVisited.getCondition())) leaveCall();

    config.getIndentor().indent();
    // we have to check this to generate valid code for this style: "return
    // if true", because there is no newline
    if (!isStartOnNewLine(iVisited.getCondition(), iVisited.getThenBody()) && iVisited.getThenBody() != null) {
      printNewlineAndIndentation();
        }

    visitNode(iVisited.getThenBody());
    config.getIndentor().outdent();
    Node elseNode = printElsIfNodes(iVisited.getElseBody());

    if (elseNode != null) {
      printNewlineAndIndentation();
      print("else");
      config.getIndentor().indent();
      visitNode(elseNode);
      config.getIndentor().outdent();
    }
    printNewlineAndIndentation();
    print("end");
    return null;
  }

  private boolean isOnSingleLine(Node n) {
    return isOnSingleLine(n, n);
  }

  private boolean isOnSingleLine(Node n1, Node n2) {
    if (n1 == null || n2 == null) return false;
       
    return (getStartLine(n1) == getEndLine(n2));
  }

  private boolean printIterVarNode(IterNode n) {
    if (n.getVarNode() == null) return false;
       
        print('|');
        visitNode(n.getVarNode());
        print('|');
       
        return true;
  }

  public Instruction visitIterNode(IterNode iVisited) {
    if (isOnSingleLine(iVisited)) {
      print(config.getFormatHelper().beforeIterBrackets());
      print("{");
      print(config.getFormatHelper().beforeIterVars());
      if(printIterVarNode(iVisited)) print(config.getFormatHelper().afterIterVars());
      config.setSkipNextNewline(true);
      visitNode(iVisited.getBodyNode());
      print(config.getFormatHelper().beforeClosingIterBrackets());
      print('}');
    } else {
      print(" do ");
      printIterVarNode(iVisited);
      visitNodeInIndentation(iVisited.getBodyNode());
      printNewlineAndIndentation();
      print("end");
    }
    return null;
  }

  public Instruction visitLocalAsgnNode(LocalAsgnNode iVisited) {
    config.getLocalVariables().addLocalVariable(iVisited.getIndex(), iVisited.getName());
    printAsgnNode(iVisited);
    return null;
  }

  public Instruction visitLocalVarNode(LocalVarNode iVisited) {
    print(iVisited.getName());
    return null;
  }

  public Instruction visitMultipleAsgnNode(MultipleAsgnNode iVisited) {
    if (iVisited.getHeadNode() != null) {
      factory.createMultipleAssignmentReWriteVisitor().visitAndPrintWithSeparator(iVisited.getHeadNode().childNodes().iterator());
        }
    if (iVisited.getValueNode() == null || iVisited.getValueNode().isInvisible()) {
      visitNode(iVisited.getArgsNode());
      return null;
    }
    print(config.getFormatHelper().beforeAssignment());
    print("=");
    print(config.getFormatHelper().afterAssignment());
    enterCall();
    if (iVisited.getValueNode() instanceof ArrayNode) {
      visitAndPrintWithSeparator(iVisited.getValueNode().childNodes().iterator());
        } else {
      visitNode(iVisited.getValueNode());
        }
    leaveCall();
    return null;
  }

  public Instruction visitMatch2Node(Match2Node iVisited) {
    visitNode(iVisited.getReceiverNode());
    print(config.getFormatHelper().matchOperator());
    enterCall();
    visitNode(iVisited.getValueNode());
    leaveCall();
    return null;
  }

  public Instruction visitMatch3Node(Match3Node iVisited) {
    visitNode(iVisited.getValueNode());
    print(config.getFormatHelper().matchOperator());
    visitNode(iVisited.getReceiverNode());
    return null;
  }

  public Instruction visitMatchNode(MatchNode iVisited) {
    visitNode(iVisited.getRegexpNode());
    return null;
  }

  public Instruction visitModuleNode(ModuleNode iVisited) {
    print("module ");
    config.getIndentor().indent();
    visitNode(iVisited.getCPath());
    visitNode(iVisited.getBodyNode());
    config.getIndentor().outdent();
    printNewlineAndIndentation();
    print("end");
    return null;
  }
 
  public Instruction visitNewlineNode(NewlineNode iVisited) {
    if (config.isSkipNextNewline()) {
      config.setSkipNextNewline(false);
    } else {
      printNewlineAndIndentation();
    }
    visitNode(iVisited.getNextNode());
    return null;
  }

  public Instruction visitNextNode(NextNode iVisited) {
    print("next");
    return null;
  }

  public Instruction visitNilNode(NilNode iVisited) {
    print("nil");
    return null;
  }

  public Instruction visitNotNode(NotNode iVisited) {
    if (iVisited.getConditionNode() instanceof CallNode) enterCall();
       
    print(sourceRangeContains(iVisited.getPosition(), "not") ? "not " : "!");
    visitNewlineInParentheses(iVisited.getConditionNode());

    if (iVisited.getConditionNode() instanceof CallNode) leaveCall();
       
    return null;
  }

  public Instruction visitNthRefNode(NthRefNode iVisited) {
    print('$');
    print(iVisited.getMatchNumber());
    return null;
  }

  private boolean isSimpleNode(Node n) {
    return (n instanceof LocalVarNode || n instanceof AssignableNode
        || n instanceof InstVarNode || n instanceof ClassVarNode
        || n instanceof GlobalVarNode || n instanceof ConstDeclNode
        || n instanceof VCallNode || isNumericNode(n));
  }

  public Instruction visitOpElementAsgnNode(OpElementAsgnNode iVisited) {

    if (!isSimpleNode(iVisited.getReceiverNode())) {
      visitNewlineInParentheses(iVisited.getReceiverNode());
        } else {
      visitNode(iVisited.getReceiverNode());
        }

    visitNode(iVisited.getArgsNode());
    print(' ');
    print(iVisited.getOperatorName());
    print("=");
    print(config.getFormatHelper().afterAssignment());
    visitNode(iVisited.getValueNode());
    return null;
  }

  public Instruction visitOpAsgnNode(OpAsgnNode iVisited) {
    visitNode(iVisited.getReceiverNode());
    print('.');
    print(iVisited.getVariableName());
    print(' ');
    print(iVisited.getOperatorName());
    print("=");
    print(config.getFormatHelper().afterAssignment());
    visitNode(iVisited.getValueNode());
    return null;
  }

  private void printOpAsgnNode(Node n, String operator) {
    enterCall();
   
    print(((INameNode) n).getName());
    print(config.getFormatHelper().beforeAssignment());
    print(operator);
    print(config.getFormatHelper().afterAssignment());
    visitNode(((AssignableNode) n).getValueNode());
     
    leaveCall();
  }

  public Instruction visitOpAsgnAndNode(OpAsgnAndNode iVisited) {
    printOpAsgnNode(iVisited.getSecondNode(), "&&=");
    return null;
  }

  public Instruction visitOpAsgnOrNode(OpAsgnOrNode iVisited) {
    printOpAsgnNode(iVisited.getSecondNode(), "||=");
    return null;
  }

  public Instruction visitOrNode(OrNode iVisited) {
    enterCall();
    visitNode(iVisited.getFirstNode());
    leaveCall();
       
    print(sourceRangeContains(iVisited.getPosition(), "||") ? " || " : " or ");
       
    enterCall();
    visitNewlineInParentheses(iVisited.getSecondNode());
    leaveCall();
       
    return null;
  }

  public Instruction visitPostExeNode(PostExeNode iVisited) {
    // this node contains nothing but an empty list, so we don't have to
    // process anything
    return null;
  }

    public Instruction visitPreExeNode(PreExeNode iVisited) {
        // this node contains nothing but an empty list, so we don't have to
        // process anything
        return null;
    }

    public Instruction visitRedoNode(RedoNode iVisited) {
    print("redo");
    return null;
  }

  private String getFirstRegexpEnclosure(Node n) {
    return isSpecialRegexNotation(n) ? "%r(" : "/";
  }

  private String getSecondRegexpEnclosure(Node n) {
    return isSpecialRegexNotation(n) ? ")" : "/";
  }

  private boolean isSpecialRegexNotation(Node n) {
    return getStartOffset(n) >= 2
      && !(config.getSource().length() < getStartOffset(n))
      && config.getSource().charAt(getStartOffset(n) - 3) == '%';
  }

  private void printRegexpOptions(int option) {
    if ((option & 1) == 1) print('i');
    if ((option & 2) == 2) print('x');
    if ((option & 4) == 4) print('m');
  }

  public Instruction visitRegexpNode(RegexpNode iVisited) {
    print(getFirstRegexpEnclosure(iVisited));
    print(iVisited.getValue().toString());
    print(getSecondRegexpEnclosure(iVisited));
    printRegexpOptions(iVisited.getOptions());
    return null;
  }

  public static Node firstChild(Node n) {
    if (n == null || n.childNodes().size() <= 0) return null;
       
    return (Node) n.childNodes().get(0);
  }

  public Instruction visitRescueBodyNode(RescueBodyNode iVisited) {
    if (!iVisited.getBodyNode().isInvisible() && config.getLastPosition().getStartLine() == getEndLine(iVisited.getBodyNode())) {
      print(" rescue ");
    } else {
      print("rescue");
    }

    if (iVisited.getExceptionNodes() != null) {
      printExceptionNode(iVisited);
    } else {
      visitNodeInIndentation(iVisited.getBodyNode());
    }
       
    if (iVisited.getOptRescueNode() != null) printNewlineAndIndentation();
       
    visitNode(iVisited.getOptRescueNode());
    return null;
  }

  private void printExceptionNode(RescueBodyNode n) {
    if (n.getExceptionNodes() == null) return;

    print(' ');
    visitNode(firstChild(n.getExceptionNodes()));

    Node firstBodyNode = n.getBodyNode();
    if (n.getBodyNode() instanceof BlockNode) firstBodyNode = firstChild(n.getBodyNode());

    // if the exception is assigned to a variable, we have to skip the first
    // node in the body
    if (firstBodyNode instanceof AssignableNode) {
      print(config.getFormatHelper().beforeAssignment());
      print("=>");
      print(config.getFormatHelper().afterAssignment());
      print(((INameNode) firstBodyNode).getName());
      if (firstBodyNode instanceof LocalAsgnNode)
        config.getLocalVariables().addLocalVariable(((LocalAsgnNode) firstBodyNode).getIndex(),
            ((LocalAsgnNode) firstBodyNode).getName());

      config.getIndentor().indent();
      visitIterAndSkipFirst(n.getBodyNode().childNodes().iterator());
      config.getIndentor().outdent();
    } else {
      visitNodeInIndentation(n.getBodyNode());
        }
  }

  public Instruction visitRescueNode(RescueNode iVisited) {
    visitNode(iVisited.getBodyNode());
    config.getIndentor().outdent();

    if (!iVisited.getRescueNode().getBodyNode().isInvisible()
        && getStartLine(iVisited) != getEndLine(iVisited.getRescueNode().getBodyNode())) {
      printNewlineAndIndentation();
        }

    if (iVisited.getRescueNode().getBodyNode().isInvisible()) {
      printNewlineAndIndentation();
      print("rescue");
      printExceptionNode(iVisited.getRescueNode());
    } else {
      visitNode(iVisited.getRescueNode());
    }
       
    if (iVisited.getElseNode() != null) {
      printNewlineAndIndentation();
      print("else");
      visitNodeInIndentation(iVisited.getElseNode());
    }
       
    config.getIndentor().indent();
    return null;
  }

  public Instruction visitRetryNode(RetryNode iVisited) {
    print("retry");
    return null;
  }

  public static Node unwrapSingleArrayNode(Node n) {
    if (!(n instanceof ArrayNode)) return n;
    if (((ArrayNode) n).childNodes().size() > 1) return n;
       
    return firstChild((ArrayNode) n);
  }

  public Instruction visitReturnNode(ReturnNode iVisited) {
    print("return");
    enterCall();
    if (!iVisited.getValueNode().isInvisible()) {
      print(' ');
      visitNode(unwrapSingleArrayNode(iVisited.getValueNode()));
    }
    leaveCall();
    return null;
  }

  public Instruction visitSClassNode(SClassNode iVisited) {
    print("class << ");
    config.getIndentor().indent();
    visitNode(iVisited.getReceiverNode());
    visitNode(iVisited.getBodyNode());
    config.getIndentor().outdent();
    printNewlineAndIndentation();
    print("end");
    return null;
  }
 
  public Instruction visitSelfNode(SelfNode iVisited) {
    print("self");
    return null;
  }

  public Instruction visitSplatNode(SplatNode iVisited) {
    print("*");
    visitNode(iVisited.getValue());
    return null;
  }

  private boolean stringIsHereDocument(StrNode n) {
    return sourceRangeEquals(getStartOffset(n) + 1, getStartOffset(n) + 3, "<<") ||
            sourceRangeEquals(getStartOffset(n), getStartOffset(n) + 3, "<<-");
  }

    protected char getSeparatorForSym(Node n) {
        // ENEBO: I added one since a sym will start with ':'...This seems like an incomplete assumption
        if (config.getSource().length() >= (getStartOffset(n)+1) &&
                config.getSource().charAt(getStartOffset(n)+1) == '\'') {
            return '\'';
        }
        return '"';
    }

  protected char getSeparatorForStr(Node n) {
    if (config.getSource().length() >= getStartOffset(n) &&
                config.getSource().charAt(getStartOffset(n)) == '\'') {
      return '\'';
    }
    return '"';
  }
 
  protected boolean inDRegxNode() {
    return false;
  }

  public Instruction visitStrNode(StrNode iVisited) {
    // look for a here-document:
    if (stringIsHereDocument(iVisited)) {
      print("<<-EOF");
      config.depositHereDocument(iVisited.getValue().toString());
      return null;
    }
   
    if(iVisited.getValue().equals("")) {
      if(config.getPrintQuotesInString().isTrue()) print("\"\"");
     
      return null;
    }

    // don't print quotes if we are a subpart of an other here-document
    if (config.getPrintQuotesInString().isTrue()) print(getSeparatorForStr(iVisited));

    if (inDRegxNode()) {
      print(iVisited.getValue().toString());
        } else {
      Matcher matcher = Pattern.compile("([\\\\\\n\\f\\r\\t\\\"\\\'])").matcher(iVisited.getValue().toString());

      if (matcher.find()) {
        String unescChar = unescapeChar(matcher.group(1).charAt(0));
        print(matcher.replaceAll("\\\\" + unescChar));
      } else {
        print(iVisited.getValue().toString());
      }
    }
    if (config.getPrintQuotesInString().isTrue()) print(getSeparatorForStr(iVisited));

    return null;
  }

  public static String unescapeChar(char escapedChar) {
    switch (escapedChar) {
    case '\n':
      return "n";
    case '\f':
      return "f";
    case '\r':
      return "r";
    case '\t':
      return "t";
    case '\"':
      return "\"";
    case '\'':
      return "'";
    case '\\':
      return "\\\\";
    default:
      return null;
    }
  }

  private boolean needsSuperNodeParentheses(SuperNode n) {
    return n.getArgsNode().childNodes().isEmpty() &&
            config.getSource().charAt(getEndOffset(n)) == '(';
  }

  public Instruction visitSuperNode(SuperNode iVisited) {
    print("super");
    if (needsSuperNodeParentheses(iVisited)) print('(');
       
    printCallArguments(iVisited.getArgsNode(), iVisited.getIterNode());
       
    if (needsSuperNodeParentheses(iVisited)) print(')');
       
    return null;
  }

  public Instruction visitSValueNode(SValueNode iVisited) {
    visitNode(iVisited.getValue());
    return null;
  }

  public Instruction visitSymbolNode(SymbolNode iVisited) {
    print(':');
    print(iVisited.getName());
    return null;
  }

  public Instruction visitToAryNode(ToAryNode iVisited) {
    visitNode(iVisited.getValue());
    return null;
  }

  public Instruction visitTrueNode(TrueNode iVisited) {
    print("true");
    return null;
  }

  public Instruction visitUndefNode(UndefNode iVisited) {
    print("undef ");
    print(iVisited.getName());
    return null;
  }

  public Instruction visitUntilNode(UntilNode iVisited) {
    print("until ");
    visitNode(iVisited.getConditionNode());
    visitNodeInIndentation(iVisited.getBodyNode());
    printNewlineAndIndentation();
    print("end");
    return null;
  }

  public Instruction visitVAliasNode(VAliasNode iVisited) {
    print("alias ");
    print(iVisited.getNewName());
    print(' ');
    print(iVisited.getOldName());
    return null;
  }

  public Instruction visitVCallNode(VCallNode iVisited) {
    print(iVisited.getName());
    return null;
  }

  public void visitNodeInIndentation(Node n) {
    config.getIndentor().indent();
    visitNode(n);
    config.getIndentor().outdent();
  }

  public Instruction visitWhenNode(WhenNode iVisited) {
    printNewlineAndIndentation();
    print("when ");
    enterCall();
    visitAndPrintWithSeparator(iVisited.getExpressionNodes().childNodes().iterator());
    leaveCall();
    visitNodeInIndentation(iVisited.getBodyNode());
    if ((iVisited.getNextCase() instanceof WhenNode || iVisited.getNextCase() == null)) {
      visitNode(iVisited.getNextCase());
        } else {
      printNewlineAndIndentation();
      print("else");
      visitNodeInIndentation(iVisited.getNextCase());
    }
    return null;
  }

  protected void visitNewlineInParentheses(Node n) {
    if (n instanceof NewlineNode) {
      if (((NewlineNode) n).getNextNode() instanceof SplatNode) {
        print('[');
        visitNode(((NewlineNode) n).getNextNode());
        print(']');
      } else {
        print('(');
        visitNode(((NewlineNode) n).getNextNode());
        print(')');
      }
    } else {
      visitNode(n);
    }
  }
 
  private void printWhileStatement(WhileNode iVisited) {
    print("while ");
   
    if (isAssignment(iVisited.getConditionNode())) enterCall();
   
    visitNewlineInParentheses(iVisited.getConditionNode());
   
    if (isAssignment(iVisited.getConditionNode())) leaveCall();
   
    visitNodeInIndentation(iVisited.getBodyNode());
   
    printNewlineAndIndentation();
    print("end");
  }
 
  private void printDoWhileStatement(WhileNode iVisited) {
    print("begin");
    visitNodeInIndentation(iVisited.getBodyNode());
    printNewlineAndIndentation();
    print("end while ");
    visitNode(iVisited.getConditionNode());
  }

  public Instruction visitWhileNode(WhileNode iVisited) {
    if (iVisited.evaluateAtStart()) {
      printWhileStatement(iVisited);
    } else {
      printDoWhileStatement(iVisited);
    }
    return null;
  }

  public Instruction visitXStrNode(XStrNode iVisited) {
    print('`');
    print(iVisited.getValue().toString());
    print('`');
    return null;
  }

  public Instruction visitYieldNode(YieldNode iVisited) {
    print("yield");
   
    if (iVisited.getArgsNode() != null) {
      print(needsParentheses(iVisited.getArgsNode()) ? '(' : ' ');

      enterCall();

      if (iVisited.getArgsNode() instanceof ArrayNode) {
        visitAndPrintWithSeparator(iVisited.getArgsNode().childNodes().iterator());
            } else {
        visitNode(iVisited.getArgsNode());
            }

      leaveCall();

      if (needsParentheses(iVisited.getArgsNode())) print(')');
    }
    return null;
  }

  public Instruction visitZArrayNode(ZArrayNode iVisited) {
    print("[]");
    return null;
  }

  public Instruction visitZSuperNode(ZSuperNode iVisited) {
    print("super");
    return null;
  }

  private static int getStartLine(Node n) {
    return n.getPosition().getStartLine();
  }

  private static int getStartOffset(Node n) {
    return n.getPosition().getStartOffset();
  }

  private static int getEndLine(Node n) {
    return n.getPosition().getEndLine();
  }

  protected static int getEndOffset(Node n) {
    return n.getPosition().getEndOffset();
  }

  public ReWriterContext getConfig() {
    return config;
  }
 
  public static String createCodeFromNode(Node node, String document){
    return createCodeFromNode(node, document, new DefaultFormatHelper());
  }
 
  public static String createCodeFromNode(Node node, String document, FormatHelper helper){
    StringWriter writer = new StringWriter();
    ReWriterContext ctx = new ReWriterContext(writer, document, helper);
    ReWriteVisitor rewriter = new ReWriteVisitor(ctx);
    rewriter.visitNode(node);
    return writer.toString();
  }

  public Instruction visitArgsPushNode(ArgsPushNode node) {
    assert false : "Unhandled node";
    return null;
  }

  public Instruction visitAttrAssignNode(AttrAssignNode iVisited) {   
    if (iVisited.getName().equals("[]=")) return printIndexAssignment(iVisited);
       
    if (iVisited.getName().endsWith("=")) {
      visitNode(iVisited.getReceiverNode());
      print('.');
     
      printNameWithoutEqualSign(iVisited);
      printAssignmentOperator();
      if (iVisited.getArgsNode() != null) {
        visitAndPrintWithSeparator(iVisited.getArgsNode().childNodes().iterator());
      }
    } else {
      assert false : "Unhandled AttrAssignNode";
    }
   
    return null;
  }

  private void printNameWithoutEqualSign(INameNode iVisited) {
    print(iVisited.getName().substring(0, iVisited.getName().length() - 1));
  }

  public Instruction visitRootNode(RootNode iVisited) {
    config.getLocalVariables().addLocalVariable(iVisited.getStaticScope());
    visitNode(iVisited.getBodyNode());
    if (config.hasHereDocument()) config.fetchHereDocument().print();

    return null;
  }
}
TOP

Related Classes of org.jruby.ast.visitor.rewriter.ReWriteVisitor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.