/*
* Author: C.Williams
*
* Copyright (c) 2004 RubyPeople.
*
* This file is part of the Ruby Development Tools (RDT) plugin for eclipse. You
* can get copy of the GPL along with further information about RubyPeople and
* third party software bundled with RDT in the file
* org.rubypeople.rdt.core_x.x.x/RDT.license or otherwise at
* http://www.rubypeople.org/RDT.license.
*
* RDT is free software; you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later
* version.
*
* RDT is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* RDT; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
* Suite 330, Boston, MA 02111-1307 USA
*/
package org.rubypeople.rdt.internal.core;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import org.jruby.ast.AliasNode;
import org.jruby.ast.ArgsNode;
import org.jruby.ast.ArgumentNode;
import org.jruby.ast.ArrayNode;
import org.jruby.ast.AssignableNode;
import org.jruby.ast.CallNode;
import org.jruby.ast.ClassNode;
import org.jruby.ast.ClassVarAsgnNode;
import org.jruby.ast.ClassVarDeclNode;
import org.jruby.ast.ClassVarNode;
import org.jruby.ast.Colon2Node;
import org.jruby.ast.ConstDeclNode;
import org.jruby.ast.ConstNode;
import org.jruby.ast.DAsgnNode;
import org.jruby.ast.DStrNode;
import org.jruby.ast.DefnNode;
import org.jruby.ast.DefsNode;
import org.jruby.ast.FCallNode;
import org.jruby.ast.GlobalAsgnNode;
import org.jruby.ast.GlobalVarNode;
import org.jruby.ast.InstAsgnNode;
import org.jruby.ast.InstVarNode;
import org.jruby.ast.IterNode;
import org.jruby.ast.ListNode;
import org.jruby.ast.LocalAsgnNode;
import org.jruby.ast.LocalVarNode;
import org.jruby.ast.ModuleNode;
import org.jruby.ast.Node;
import org.jruby.ast.RootNode;
import org.jruby.ast.SClassNode;
import org.jruby.ast.SelfNode;
import org.jruby.ast.SplatNode;
import org.jruby.ast.StrNode;
import org.jruby.ast.VCallNode;
import org.jruby.ast.YieldNode;
import org.jruby.runtime.Visibility;
import org.rubypeople.rdt.core.IMethod;
import org.rubypeople.rdt.internal.compiler.ISourceElementRequestor;
import org.rubypeople.rdt.internal.compiler.ISourceElementRequestor.FieldInfo;
import org.rubypeople.rdt.internal.compiler.ISourceElementRequestor.MethodInfo;
import org.rubypeople.rdt.internal.compiler.ISourceElementRequestor.TypeInfo;
import org.rubypeople.rdt.internal.core.parser.InOrderVisitor;
import org.rubypeople.rdt.internal.core.parser.RubyParser;
import org.rubypeople.rdt.internal.core.util.ASTUtil;
/**
* @author Chris
*
*/
public class SourceElementParser extends InOrderVisitor {
private static final String MODULE_FUNCTION = "module_function";
private static final String PROTECTED = "protected";
private static final String PRIVATE = "private";
private static final String PUBLIC = "public";
private static final String INCLUDE = "include";
private static final String LOAD = "load";
private static final String REQUIRE = "require";
private static final String ALIAS = "alias :";
private static final String MODULE = "Module";
private static final String CONSTRUCTOR_NAME = "initialize";
private static final String OBJECT = "Object";
private List<Visibility> visibilities = new ArrayList<Visibility>();
private boolean inSingletonClass;
public ISourceElementRequestor requestor;
private boolean inModuleFunction;
private char[] source;
private String typeName;
/**
*
* @param requestor The {@link ISourceElementRequestor} that wants to be notified of the source structure
*/
public SourceElementParser(ISourceElementRequestor requestor) {
super();
this.requestor = requestor;
}
/*
* (non-Javadoc)
*
* @see org.jruby.ast.visitor.NodeVisitor#visitClassNode(org.jruby.ast.ClassNode)
*/
public Object visitClassNode(ClassNode iVisited) {
// This resets the visibility when opening or declaring a class to
// public
pushVisibility(Visibility.PUBLIC);
TypeInfo typeInfo = new TypeInfo();
typeInfo.name = ASTUtil.getFullyQualifiedName(iVisited.getCPath());
typeInfo.declarationStart = iVisited.getPosition().getStartOffset();
typeInfo.nameSourceStart = iVisited.getCPath().getPosition().getStartOffset();
typeInfo.nameSourceEnd = iVisited.getCPath().getPosition().getEndOffset() - 1;
if (!typeInfo.name.equals(OBJECT)) {
String superClass = ASTUtil.getSuperClassName(iVisited.getSuperNode());
typeInfo.superclass = superClass;
}
typeInfo.isModule = false;
typeInfo.modules = new String[0];
typeInfo.secondary = false; // TODO Set secondary to true if we're enclosed by another type?
typeName = typeInfo.name;
requestor.enterType(typeInfo);
Object ins = super.visitClassNode(iVisited);
popVisibility();
requestor.exitType(iVisited.getPosition().getEndOffset() - 2);
return ins;
}
@Override
public Object visitConstNode(ConstNode iVisited) {
// FIXME ConstNode could be a reference to a type, or a constant(field)!
requestor.acceptTypeReference(iVisited.getName(), iVisited.getPosition().getStartOffset(), iVisited.getPosition().getEndOffset());
return super.visitConstNode(iVisited);
}
@Override
public Object visitModuleNode(ModuleNode iVisited) {
pushVisibility(Visibility.PUBLIC);
TypeInfo typeInfo = new TypeInfo();
typeInfo.name = ASTUtil.getFullyQualifiedName(iVisited.getCPath());
typeInfo.declarationStart = iVisited.getPosition().getStartOffset();
typeInfo.nameSourceStart = iVisited.getCPath().getPosition().getStartOffset();
typeInfo.nameSourceEnd = iVisited.getCPath().getPosition().getEndOffset() - 1;
typeInfo.superclass = MODULE; // FIXME Is this really true? Should it be null?
typeInfo.isModule = true;
typeInfo.modules = new String[0];
typeInfo.secondary = false; // TODO Set secondary to true if we're enclosed by another type?
typeName = typeInfo.name;
requestor.enterType(typeInfo);
Object ins = super.visitModuleNode(iVisited);
popVisibility();
requestor.exitType(iVisited.getPosition().getEndOffset() - 2);
inModuleFunction = false;
return ins;
}
@Override
public Object visitDefnNode(DefnNode iVisited) {
Visibility visibility = getCurrentVisibility();
MethodInfo methodInfo = new MethodInfo();
methodInfo.declarationStart = iVisited.getPosition().getStartOffset();
methodInfo.name = iVisited.getName();
methodInfo.nameSourceStart = iVisited.getNameNode().getPosition().getStartOffset();
methodInfo.nameSourceEnd = iVisited.getNameNode().getPosition().getEndOffset() - 1;
if (methodInfo.name.equals(CONSTRUCTOR_NAME)) {
visibility = Visibility.PROTECTED;
methodInfo.isConstructor = true;
} else {
methodInfo.isConstructor = false;
}
methodInfo.isClassLevel = inSingletonClass || inModuleFunction;
methodInfo.visibility = convertVisibility(visibility);
methodInfo.parameterNames = ASTUtil.getArgs(iVisited.getArgsNode(), iVisited.getScope());
if (methodInfo.isConstructor) {
requestor.enterConstructor(methodInfo);
} else {
requestor.enterMethod(methodInfo);
}
Object ins = super.visitDefnNode(iVisited); // now traverse it's body
int end = iVisited.getPosition().getEndOffset() - 2;
if (methodInfo.isConstructor) {
requestor.exitConstructor(end);
} else {
requestor.exitMethod(end);
}
return ins;
}
@Override
public Object visitArgsNode(ArgsNode iVisited) {
// Add args as local vars!
ListNode list = iVisited.getArgs();
if (list != null) {
for (int i = 0; i < list.size(); i++) {
Node arg = list.get(i);
FieldInfo field = new FieldInfo();
field.declarationStart = arg.getPosition().getStartOffset();
field.nameSourceStart = arg.getPosition().getStartOffset();
String name = ASTUtil.getNameReflectively(arg);
field.nameSourceEnd = arg.getPosition().getStartOffset()
+ name.length() - 1;
field.name = name;
requestor.enterField(field);
requestor.exitField(arg.getPosition().getEndOffset() - 1);
}
}
ArgumentNode arg = iVisited.getRestArgNode();
if (arg != null) {
FieldInfo field = new FieldInfo();
field.declarationStart = arg.getPosition().getStartOffset() + 1;
field.nameSourceStart = arg.getPosition().getStartOffset() + 1;
String name = ASTUtil.getNameReflectively(arg);
field.nameSourceEnd = arg.getPosition().getStartOffset() + name.length();
field.name = name;
requestor.enterField(field);
requestor.exitField(arg.getPosition().getEndOffset());
}
return super.visitArgsNode(iVisited);
}
@Override
public Object visitDefsNode(DefsNode iVisited) {
MethodInfo methodInfo = new MethodInfo();
methodInfo.declarationStart = iVisited.getPosition().getStartOffset();
methodInfo.name = iVisited.getName();
methodInfo.nameSourceStart = iVisited.getNameNode().getPosition().getStartOffset();
methodInfo.nameSourceEnd = iVisited.getNameNode().getPosition().getEndOffset() - 1;
methodInfo.isConstructor = false;
methodInfo.isClassLevel = true;
methodInfo.visibility = convertVisibility(getCurrentVisibility());
methodInfo.parameterNames = ASTUtil.getArgs(iVisited.getArgsNode(), iVisited.getScope());
requestor.enterMethod(methodInfo);
Object ins = super.visitDefsNode(iVisited); // now traverse it's body
requestor.exitMethod(iVisited.getPosition().getEndOffset() - 2);
return ins;
}
/**
* @param visibility
* @return
*/
private int convertVisibility(Visibility visibility) {
// FIXME What about the module function and public-protected
// visibilities?
if (visibility == Visibility.PUBLIC)
return IMethod.PUBLIC;
if (visibility == Visibility.PROTECTED)
return IMethod.PROTECTED;
return IMethod.PRIVATE;
}
@Override
public Object visitRootNode(RootNode iVisited) {
requestor.enterScript();
pushVisibility(Visibility.PUBLIC);
Object ins = super.visitRootNode(iVisited);
popVisibility();
requestor.exitScript(iVisited.getPosition().getEndOffset());
return ins;
}
private void popVisibility() {
visibilities.remove(visibilities.size() - 1);
}
@Override
public Object visitConstDeclNode(ConstDeclNode iVisited) {
FieldInfo field = createFieldInfo(iVisited);
field.name = iVisited.getName();
requestor.enterField(field);
exitField(iVisited);
return super.visitConstDeclNode(iVisited);
}
public Object visitClassVarAsgnNode(ClassVarAsgnNode iVisited) {
FieldInfo field = createFieldInfo(iVisited);
field.name = iVisited.getName();
requestor.enterField(field);
exitField(iVisited);
return super.visitClassVarAsgnNode(iVisited);
}
@Override
public Object visitClassVarDeclNode(ClassVarDeclNode iVisited) {
FieldInfo field = createFieldInfo(iVisited);
field.name = iVisited.getName();
requestor.enterField(field);
exitField(iVisited);
return super.visitClassVarDeclNode(iVisited);
}
@Override
public Object visitClassVarNode(ClassVarNode iVisited) {
requestor.acceptFieldReference(iVisited.getName(), iVisited.getPosition().getStartOffset());
return super.visitClassVarNode(iVisited);
}
public Object visitLocalAsgnNode(LocalAsgnNode iVisited) {
FieldInfo field = createFieldInfo(iVisited);
field.name = iVisited.getName();
requestor.enterField(field);
exitField(iVisited);
return super.visitLocalAsgnNode(iVisited);
}
@Override
public Object visitInstAsgnNode(InstAsgnNode iVisited) {
FieldInfo field = createFieldInfo(iVisited);
field.name = iVisited.getName();
requestor.enterField(field);
exitField(iVisited);
return super.visitInstAsgnNode(iVisited);
}
@Override
public Object visitInstVarNode(InstVarNode iVisited) {
requestor.acceptFieldReference(iVisited.getName(), iVisited.getPosition().getStartOffset());
return super.visitInstVarNode(iVisited);
}
@Override
public Object visitGlobalAsgnNode(GlobalAsgnNode iVisited) {
FieldInfo field = createFieldInfo(iVisited);
field.name = iVisited.getName();
requestor.enterField(field);
exitField(iVisited);
return super.visitGlobalAsgnNode(iVisited);
}
@Override
public Object visitGlobalVarNode(GlobalVarNode iVisited) {
requestor.acceptFieldReference(iVisited.getName(), iVisited.getPosition().getStartOffset());
return super.visitGlobalVarNode(iVisited);
}
private void exitField(AssignableNode iVisited) {
requestor.exitField(iVisited.getPosition().getEndOffset() - 1);
}
private FieldInfo createFieldInfo(AssignableNode iVisited) {
FieldInfo field = new FieldInfo();
field.declarationStart = iVisited.getPosition().getStartOffset();
field.nameSourceStart = iVisited.getPosition().getStartOffset();
String name = ASTUtil.getNameReflectively(iVisited);
field.nameSourceEnd = iVisited.getPosition().getStartOffset() + name.length() - 1;
return field;
}
/*
* (non-Javadoc)
*
* @see org.jruby.ast.visitor.NodeVisitor#visitIterNode(org.jruby.ast.IterNode)
*/
public Object visitIterNode(IterNode iVisited) {
requestor.acceptBlock(iVisited.getPosition().getStartOffset(), iVisited.getPosition().getEndOffset() - 1);
return super.visitIterNode(iVisited);
}
@Override
public Object visitDAsgnNode(DAsgnNode iVisited) {
FieldInfo field = createFieldInfo(iVisited);
field.name = iVisited.getName();
field.isDynamic = true;
requestor.enterField(field);
exitField(iVisited);
return super.visitDAsgnNode(iVisited);
}
@Override
public Object visitSClassNode(SClassNode iVisited) {
Node receiver = iVisited.getReceiverNode();
if (receiver instanceof SelfNode) {
inSingletonClass = true;
}
pushVisibility(Visibility.PUBLIC);
Object ins = super.visitSClassNode(iVisited);
popVisibility();
if (receiver instanceof SelfNode) {
inSingletonClass = false;
}
return ins;
}
public Object visitFCallNode(FCallNode iVisited) {
String name = iVisited.getName();
List<String> arguments = getArgumentsFromFunctionCall(iVisited);
if (name.equals(REQUIRE) || name.equals(LOAD)) {
addImport(iVisited);
} else if (name.equals(INCLUDE)) { // Collect included mixins
includeModule(iVisited);
}
if (name.equals(PUBLIC)) {
for (String methodName : arguments) {
requestor.acceptMethodVisibilityChange(methodName, convertVisibility(Visibility.PUBLIC));
}
} else if (name.equals(PRIVATE)) {
for (String methodName : arguments) {
requestor.acceptMethodVisibilityChange(methodName, convertVisibility(Visibility.PRIVATE));
}
} else if (name.equals(PROTECTED)) {
for (String methodName : arguments) {
requestor.acceptMethodVisibilityChange(methodName, convertVisibility(Visibility.PROTECTED));
}
} else if (name.equals(MODULE_FUNCTION)) {
for (String methodName : arguments) {
requestor.acceptModuleFunction(methodName);
}
}
if (name.equals("alias_method")) {
String newName = arguments.get(0).substring(1);
int nameStart = iVisited.getPosition().getStartOffset() + "alias_method :".length();
addAliasMethod(newName, iVisited.getPosition().getStartOffset(), iVisited.getPosition().getEndOffset(), nameStart);
}
if (name.equals("attr")) {
List<Node> nodes = ASTUtil.getArgumentNodesFromFunctionCall(iVisited);
generateReadMethod(arguments.get(0), nodes.get(0));
// make writable?
if (arguments.size() == 2 && arguments.get(1).equals("true")) {
Node node = nodes.get(0);
int start = node.getPosition().getEndOffset() + 2;
generateWriteMethod(arguments.get(0), start, start + arguments.get(1).length() - 1);
}
}
if (name.equals("attr_reader") || name.equals("attr_accessor")) {
List<Node> nodes = ASTUtil.getArgumentNodesFromFunctionCall(iVisited);
for (int i = 0; i < arguments.size(); i++) {
generateReadMethod(arguments.get(i), nodes.get(i));
}
}
if (name.equals("attr_writer") || name.equals("attr_accessor")) {
List<Node> nodes = ASTUtil.getArgumentNodesFromFunctionCall(iVisited);
for (int i = 0; i < arguments.size(); i++) {
generateWriteMethod(arguments.get(i), nodes.get(i));
}
}
if (name.equals("attr") || name.equals("attr_accessor") || name.equals("attr_reader") || name.equals("attr_writer")) {
List<Node> nodes = ASTUtil.getArgumentNodesFromFunctionCall(iVisited);
for (int i = 0; i < arguments.size(); i++) {
FieldInfo field = new FieldInfo();
Node node = nodes.get(i);
field.declarationStart = node.getPosition().getStartOffset() + 1;
field.name = "@" + arguments.get(i);
field.nameSourceStart = node.getPosition().getStartOffset() + 1;
field.nameSourceEnd = node.getPosition().getEndOffset() - 1;
requestor.enterField(field);
requestor.exitField(node.getPosition().getEndOffset() - 1);
}
}
requestor.acceptMethodReference(name, arguments.size(), iVisited.getPosition().getStartOffset());
return super.visitFCallNode(iVisited);
}
private void addAliasMethod(String name, int start, int end, int nameStart) {
MethodInfo method = new MethodInfo();
// TODO Use the visibility for the original method that this is aliasing?
Visibility visibility = getCurrentVisibility();
if (name.equals(CONSTRUCTOR_NAME)) {
visibility = Visibility.PROTECTED;
method.isConstructor = true;
} else {
method.isConstructor = false;
}
method.declarationStart = start;
method.isClassLevel = inSingletonClass;
method.name = name;
method.visibility = convertVisibility(visibility);
method.nameSourceStart = nameStart;
method.nameSourceEnd = nameStart + name.length() - 1;
method.parameterNames = new String[0]; // TODO Find the existing method and steal it's parameter names
requestor.enterMethod(method);
requestor.exitMethod(end);
}
private void generateWriteMethod(String argument, Node node) {
generateWriteMethod(argument, node.getPosition().getStartOffset(), node.getPosition().getEndOffset() - 1);
}
private void generateWriteMethod(String argument, int start, int end) {
if (argument.startsWith(":")) {
argument = argument.substring(1);
}
MethodInfo info = new MethodInfo();
info.declarationStart = start;
info.isClassLevel = false;
info.isConstructor = false;
info.name = argument + "=";
info.nameSourceStart = start;
info.nameSourceEnd = end;
info.visibility = IMethod.PUBLIC;
info.parameterNames = new String[] {"new_value"};
requestor.enterMethod(info);
requestor.exitMethod(end);
}
private void generateReadMethod(String argument, Node node) {
if (argument.startsWith(":")) {
argument = argument.substring(1);
}
MethodInfo info = new MethodInfo();
info.declarationStart = node.getPosition().getStartOffset();
info.isClassLevel = false;
info.isConstructor = false;
info.name = argument;
info.nameSourceStart = node.getPosition().getStartOffset();
info.nameSourceEnd = node.getPosition().getEndOffset() - 1;
info.visibility = IMethod.PUBLIC;
info.parameterNames = new String[0];
requestor.enterMethod(info);
requestor.exitMethod(node.getPosition().getEndOffset() - 1);
}
private void addImport(FCallNode iVisited) {
ArrayNode node = (ArrayNode) iVisited.getArgsNode();
String arg = getString(node);
if (arg != null) {
requestor.acceptImport(arg, iVisited.getPosition().getStartOffset(), iVisited.getPosition().getEndOffset());
}
}
/**
* @param node
* @return
*/
private String getString(ArrayNode node) {
Object tmp = node.childNodes().iterator().next();
if (tmp instanceof DStrNode) {
DStrNode dstrNode = (DStrNode) tmp;
tmp = dstrNode.childNodes().iterator().next();
}
if (tmp instanceof StrNode) {
StrNode strNode = (StrNode) tmp;
return strNode.getValue().toString();
}
return null;
}
private void includeModule(FCallNode iVisited) {
List<String> mixins = new LinkedList<String>();
Node argsNode = iVisited.getArgsNode();
Iterator iter = null;
if (argsNode instanceof SplatNode) {
SplatNode splat = (SplatNode) argsNode;
iter = splat.childNodes().iterator();
} else if (argsNode instanceof ArrayNode) {
ArrayNode arrayNode = (ArrayNode) iVisited.getArgsNode();
iter = arrayNode.childNodes().iterator();
}
for (; iter.hasNext();) {
Node mixinNameNode = (Node) iter.next();
if (mixinNameNode instanceof StrNode) {
mixins.add(((StrNode) mixinNameNode).getValue().toString());
}
if (mixinNameNode instanceof DStrNode) {
Node next = (Node) ((DStrNode) mixinNameNode).childNodes().iterator().next();
if (next instanceof StrNode) {
mixins.add(((StrNode) next).getValue().toString());
}
}
if (mixinNameNode instanceof ConstNode) {
mixins.add(((ConstNode) mixinNameNode).getName());
}
if (mixinNameNode instanceof Colon2Node) {
mixins.add(ASTUtil.getFullyQualifiedName((Colon2Node) mixinNameNode));
}
}
for (String string : mixins) {
requestor.acceptMixin(string);
}
}
public Object visitVCallNode(VCallNode iVisited) {
String functionName = iVisited.getName();
if (functionName.equals(PUBLIC)) {
setVisibility(Visibility.PUBLIC);
} else if (functionName.equals(PRIVATE)) {
setVisibility(Visibility.PRIVATE);
} else if (functionName.equals(PROTECTED)) {
setVisibility(Visibility.PROTECTED);
} else if (functionName.equals(MODULE_FUNCTION)) {
inModuleFunction = true;
}
requestor.acceptMethodReference(functionName, 0, iVisited.getPosition().getStartOffset());
return super.visitVCallNode(iVisited);
}
private void setVisibility(Visibility visibility) {
popVisibility();
pushVisibility(visibility);
}
private void pushVisibility(Visibility visibility) {
visibilities.add(visibility);
}
@Override
public Object visitCallNode(CallNode iVisited) {
String name = iVisited.getName();
List<String> arguments = getArgumentsFromFunctionCall(iVisited);
if (name.equals(PUBLIC)) {
for (String methodName : arguments) {
requestor.acceptMethodVisibilityChange(methodName, convertVisibility(Visibility.PUBLIC));
}
} else if (name.equals(PRIVATE)) {
for (String methodName : arguments) {
requestor.acceptMethodVisibilityChange(methodName, convertVisibility(Visibility.PRIVATE));
}
} else if (name.equals(PROTECTED)) {
for (String methodName : arguments) {
requestor.acceptMethodVisibilityChange(methodName, convertVisibility(Visibility.PROTECTED));
}
} else if (name.equals(MODULE_FUNCTION)) {
for (String methodName : arguments) {
requestor.acceptModuleFunction(methodName);
}
} else if (name.equals("class_eval")) {
Node receiver = iVisited.getReceiverNode();
if (receiver instanceof ConstNode || receiver instanceof Colon2Node) {
String receiverName = null;
if (receiver instanceof Colon2Node) {
receiverName = ASTUtil
.getFullyQualifiedName((Colon2Node) receiver);
} else {
receiverName = ASTUtil.getNameReflectively(receiver);
}
requestor.acceptMethodReference(name, arguments.size(),
iVisited.getPosition().getStartOffset());
pushVisibility(Visibility.PUBLIC);
TypeInfo typeInfo = new TypeInfo();
typeInfo.name = receiverName;
typeInfo.declarationStart = iVisited.getPosition()
.getStartOffset();
typeInfo.nameSourceStart = receiver.getPosition()
.getStartOffset();
typeInfo.nameSourceEnd = receiver.getPosition().getEndOffset() - 1;
typeInfo.isModule = false;
typeInfo.modules = new String[0];
typeInfo.secondary = false;
requestor.enterType(typeInfo);
Object ins = super.visitCallNode(iVisited);
popVisibility();
requestor.exitType(iVisited.getPosition().getEndOffset() - 2);
return ins;
}
}
requestor.acceptMethodReference(name, arguments.size(), iVisited.getPosition().getStartOffset());
return super.visitCallNode(iVisited);
}
public Object visitAliasNode(AliasNode iVisited) {
String name = iVisited.getNewName();
int nameStart = iVisited.getPosition().getStartOffset() + ALIAS.length() - 1;
addAliasMethod(name, iVisited.getPosition().getStartOffset(), iVisited.getPosition().getEndOffset(), nameStart);
return super.visitAliasNode(iVisited);
}
private Visibility getCurrentVisibility() {
return visibilities.get(visibilities.size() - 1);
}
public void parse(char[] source, char[] name) {
RubyParser p = new RubyParser();
this.source = source;
if (name == null) name = new char[0];
Node ast = p.parse(new String(name), new String(source)).getAST();
acceptNode(ast);
}
@Override
public Object visitYieldNode(YieldNode iVisited) {
Node argsNode = iVisited.getArgsNode();
if (argsNode instanceof LocalVarNode) {
requestor.acceptYield(((LocalVarNode) argsNode).getName());
} else if (argsNode instanceof SelfNode) {
String name = null;
if (typeName == null) {
name = "var";
} else {
name = typeName.toLowerCase();
if (name.indexOf("::") > -1) {
name = name.substring(name.lastIndexOf("::") + 2);
}
}
requestor.acceptYield(name);
}
return super.visitYieldNode(iVisited);
}
}