package org.rubypeople.rdt.core.parser;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.jruby.ast.BlockNode;
import org.jruby.ast.CaseNode;
import org.jruby.ast.IfNode;
import org.jruby.ast.ListNode;
import org.jruby.ast.NewlineNode;
import org.jruby.ast.Node;
import org.jruby.ast.OpAsgnAndNode;
import org.jruby.ast.OpAsgnNode;
import org.jruby.ast.OpAsgnOrNode;
import org.jruby.ast.OpElementAsgnNode;
import org.jruby.ast.ReturnNode;
import org.jruby.ast.RootNode;
import org.jruby.ast.WhenNode;
import org.rubypeople.rdt.internal.core.parser.InOrderVisitor;
/**
* @author Chris Williams (cwilliams@aptana.com)
*/
public class ReturnVisitor extends InOrderVisitor
{
private boolean implicit = false;
private Set<ReturnVisitor> branches = new HashSet<ReturnVisitor>();
private List<Node> values = new ArrayList<Node>();
private Node lastNode;
@Override
protected Object visitNode(Node iVisited)
{
if (iVisited != null && !structuralNode(iVisited) && !branchingNode(iVisited)
&& !(iVisited instanceof ReturnNode))
{
implicit = true;
lastNode = iVisited;
}
return super.visitNode(iVisited);
}
@Override
public Object visitOpAsgnAndNode(OpAsgnAndNode iVisited)
{
handleNode(iVisited);
acceptNode(iVisited.getFirstNode());
return null;
}
@Override
public Object visitOpAsgnNode(OpAsgnNode iVisited)
{
handleNode(iVisited);
acceptNode(iVisited.getReceiverNode());
return null;
}
@Override
public Object visitOpAsgnOrNode(OpAsgnOrNode iVisited)
{
handleNode(iVisited);
acceptNode(iVisited.getFirstNode());
return null;
}
private boolean structuralNode(Node visited)
{
return (visited instanceof RootNode) || (visited instanceof NewlineNode);
}
private boolean branchingNode(Node visited)
{
return (visited instanceof IfNode) || (visited instanceof CaseNode);
}
@Override
public Object visitReturnNode(ReturnNode iVisited)
{
implicit = false;
lastNode = null;
values.add(iVisited);
return null;
}
@Override
public Object visitCaseNode(CaseNode iVisited)
{
ListNode node = iVisited.getCases();
List<Node> caseChildren = node.childNodes();
WhenNode whenNode = (WhenNode) caseChildren.get(0);
while (whenNode != null)
{
ReturnVisitor visitor = new ReturnVisitor();
whenNode.getBodyNode().accept(visitor);
branches.add(visitor);
Node nextCase = whenNode.getNextCase();
if (nextCase instanceof BlockNode)
{
ReturnVisitor visitor2 = new ReturnVisitor();
nextCase.accept(visitor2);
branches.add(visitor);
whenNode = null;
break;
}
if (nextCase instanceof NewlineNode)
{
NewlineNode newline = (NewlineNode) nextCase;
nextCase = newline.getNextNode();
}
if (nextCase instanceof WhenNode)
{
whenNode = (WhenNode) whenNode.getNextCase();
}
else
{
whenNode = null;
}
}
return null;
}
@Override
public Object visitIfNode(IfNode iVisited)
{
if (iVisited.getThenBody() != null)
{
ReturnVisitor visitor = new ReturnVisitor();
iVisited.getThenBody().accept(visitor);
branches.add(visitor);
}
if (iVisited.getElseBody() != null)
{
ReturnVisitor visitor = new ReturnVisitor();
iVisited.getElseBody().accept(visitor);
branches.add(visitor);
}
else
{
implicit = true;
}
return null;
}
public boolean alwaysExplicit()
{
for (ReturnVisitor visitor : branches)
{
if (!visitor.alwaysExplicit())
return false;
}
return !implicit;
}
public List<Node> getReturnValues()
{
if (lastNode != null)
{
values.add(lastNode);
}
for (ReturnVisitor visitor : branches)
{
values.addAll(visitor.getReturnValues());
}
return values;
}
}