package org.rubypeople.rdt.internal.ti.util;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import org.jruby.ast.ArgsNode;
import org.jruby.ast.ArgumentNode;
import org.jruby.ast.Node;
import org.jruby.lexer.yacc.ISourcePosition;
/**
* Visitor to find all nodes within a specific scope adhering to a certain condition.
*
* @author Jason Morrison
*/
public class ScopedNodeLocator extends NodeLocator
{
// Singleton pattern
private ScopedNodeLocator()
{
}
private static ScopedNodeLocator staticInstance = new ScopedNodeLocator();
public static ScopedNodeLocator Instance()
{
return staticInstance;
}
/** INodeAcceptor that defines the desired node. */
private INodeAcceptor acceptor;
/** Running total of results */
private List<Node> locatedNodes;
/**
* Finds the first node preceding the given offset that is accepted by the acceptor.
*
* @param rootNode
* Root Node that contains all nodes to search.
* @param acceptor
* INodeAcceptor defining the condition which the desired node fulfills.
* @return List of located nodes.
*/
public List<Node> findNodesInScope(Node rootNode, INodeAcceptor acceptor)
{
if (rootNode == null || acceptor == null)
return null;
locatedNodes = new LinkedList<Node>();
this.acceptor = acceptor;
// Traverse to find all matches
rootNode.accept(this);
// Return the matches
return locatedNodes;
}
/**
* Searches via InOrderVisitor for matches
*/
public Object handleNode(Node iVisited)
{
if (acceptor.doesAccept(iVisited))
{
locatedNodes.add(iVisited);
}
return super.handleNode(iVisited);
}
/**
* Handle the parsing of ArgsNode, to get at its ArgumentNodes
*
* @see org.jruby.ast.visitor.NodeVisitor#visitArgsNode(org.jruby.ast.ArgsNode)
*/
public Object visitArgsNode(ArgsNode iVisited)
{
if (iVisited.getRequiredArgsCount() > 0)
{
for (Iterator<Node> iter = iVisited.getPre().childNodes().iterator(); iter.hasNext();)
{
ArgumentNode argNode = (ArgumentNode) iter.next();
if (acceptor.doesAccept(argNode))
{
locatedNodes.add(argNode);
}
}
}
ArgumentNode argNode = iVisited.getRestArgNode();
if (argNode != null)
{
if (acceptor.doesAccept(argNode))
{
ISourcePosition pos = argNode.getPosition();
pos.adjustStartOffset(1); // Rest args are off by one...
argNode.setPosition(pos);
locatedNodes.add(argNode);
}
}
return super.visitArgsNode(iVisited);
//
// handleNode(iVisited);
// acceptNode(iVisited.getBlockArgNode());
// if (iVisited.getOptArgs() != null) {
// visitIter(iVisited.getOptArgs().iterator());
// }
// return null;
}
}