blob: 425989d9cc5e4323d276e5566a2dd3fbced7c3dd [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2016 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
*******************************************************************************/
package org.eclipse.dltk.ruby.internal.parsers.jruby;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.regex.Pattern;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.Platform;
import org.eclipse.dltk.ast.ASTNode;
import org.eclipse.dltk.ast.Modifiers;
import org.eclipse.dltk.ast.declarations.Argument;
import org.eclipse.dltk.ast.declarations.MethodDeclaration;
import org.eclipse.dltk.ast.declarations.ModuleDeclaration;
import org.eclipse.dltk.ast.declarations.TypeDeclaration;
import org.eclipse.dltk.ast.expressions.BigNumericLiteral;
import org.eclipse.dltk.ast.expressions.BooleanLiteral;
import org.eclipse.dltk.ast.expressions.CallArgumentsList;
import org.eclipse.dltk.ast.expressions.CallExpression;
import org.eclipse.dltk.ast.expressions.ExpressionConstants;
import org.eclipse.dltk.ast.expressions.FloatNumericLiteral;
import org.eclipse.dltk.ast.expressions.NilLiteral;
import org.eclipse.dltk.ast.expressions.NumericLiteral;
import org.eclipse.dltk.ast.expressions.StringLiteral;
import org.eclipse.dltk.ast.references.ConstantReference;
import org.eclipse.dltk.ast.references.SimpleReference;
import org.eclipse.dltk.ast.references.VariableReference;
import org.eclipse.dltk.ast.statements.Block;
import org.eclipse.dltk.compiler.util.Util;
import org.eclipse.dltk.ruby.ast.RubyAliasExpression;
import org.eclipse.dltk.ruby.ast.RubyArrayExpression;
import org.eclipse.dltk.ruby.ast.RubyAssignment;
import org.eclipse.dltk.ruby.ast.RubyBacktickStringLiteral;
import org.eclipse.dltk.ruby.ast.RubyBeginExpression;
import org.eclipse.dltk.ruby.ast.RubyBinaryExpression;
import org.eclipse.dltk.ruby.ast.RubyBlock;
import org.eclipse.dltk.ruby.ast.RubyBreakExpression;
import org.eclipse.dltk.ruby.ast.RubyCallArgumentsList;
import org.eclipse.dltk.ruby.ast.RubyCaseStatement;
import org.eclipse.dltk.ruby.ast.RubyClassDeclaration;
import org.eclipse.dltk.ruby.ast.RubyColonExpression;
import org.eclipse.dltk.ruby.ast.RubyConstantDeclaration;
import org.eclipse.dltk.ruby.ast.RubyDAssgnExpression;
import org.eclipse.dltk.ruby.ast.RubyDRegexpExpression;
import org.eclipse.dltk.ruby.ast.RubyDSymbolExpression;
import org.eclipse.dltk.ruby.ast.RubyDVarExpression;
import org.eclipse.dltk.ruby.ast.RubyDefinedExpression;
import org.eclipse.dltk.ruby.ast.RubyDotExpression;
import org.eclipse.dltk.ruby.ast.RubyDynamicBackquoteStringExpression;
import org.eclipse.dltk.ruby.ast.RubyDynamicStringExpression;
import org.eclipse.dltk.ruby.ast.RubyEnsureExpression;
import org.eclipse.dltk.ruby.ast.RubyEvaluatableStringExpression;
import org.eclipse.dltk.ruby.ast.RubyForStatement2;
import org.eclipse.dltk.ruby.ast.RubyHashExpression;
import org.eclipse.dltk.ruby.ast.RubyHashPairExpression;
import org.eclipse.dltk.ruby.ast.RubyIfStatement;
import org.eclipse.dltk.ruby.ast.RubyMatch2Expression;
import org.eclipse.dltk.ruby.ast.RubyMatch3Expression;
import org.eclipse.dltk.ruby.ast.RubyMatchExpression;
import org.eclipse.dltk.ruby.ast.RubyMethodArgument;
import org.eclipse.dltk.ruby.ast.RubyModuleDeclaration;
import org.eclipse.dltk.ruby.ast.RubyMultipleAssignmentStatement;
import org.eclipse.dltk.ruby.ast.RubyNextExpression;
import org.eclipse.dltk.ruby.ast.RubyNotExpression;
import org.eclipse.dltk.ruby.ast.RubyRedoExpression;
import org.eclipse.dltk.ruby.ast.RubyRegexpExpression;
import org.eclipse.dltk.ruby.ast.RubyRescueBodyStatement;
import org.eclipse.dltk.ruby.ast.RubyRescueStatement;
import org.eclipse.dltk.ruby.ast.RubyRetryExpression;
import org.eclipse.dltk.ruby.ast.RubyReturnStatement;
import org.eclipse.dltk.ruby.ast.RubySelfReference;
import org.eclipse.dltk.ruby.ast.RubySingletonClassDeclaration;
import org.eclipse.dltk.ruby.ast.RubySingletonMethodDeclaration;
import org.eclipse.dltk.ruby.ast.RubySuperExpression;
import org.eclipse.dltk.ruby.ast.RubySymbolReference;
import org.eclipse.dltk.ruby.ast.RubyUndefStatement;
import org.eclipse.dltk.ruby.ast.RubyUntilStatement;
import org.eclipse.dltk.ruby.ast.RubyVariableKind;
import org.eclipse.dltk.ruby.ast.RubyWhenStatement;
import org.eclipse.dltk.ruby.ast.RubyWhileStatement;
import org.eclipse.dltk.ruby.ast.RubyYieldExpression;
import org.eclipse.dltk.ruby.core.RubyPlugin;
import org.eclipse.dltk.ruby.core.utils.RubySyntaxUtils;
import org.eclipse.dltk.ruby.internal.parser.JRubySourceParser;
import org.eclipse.osgi.util.NLS;
import org.jruby.ast.AliasNode;
import org.jruby.ast.AndNode;
import org.jruby.ast.ArgsCatNode;
import org.jruby.ast.ArgsNode;
import org.jruby.ast.ArgsPushNode;
import org.jruby.ast.ArgumentNode;
import org.jruby.ast.ArrayNode;
import org.jruby.ast.AttrAssignNode;
import org.jruby.ast.BackRefNode;
import org.jruby.ast.BeginNode;
import org.jruby.ast.BignumNode;
import org.jruby.ast.BlockArgNode;
import org.jruby.ast.BlockNode;
import org.jruby.ast.BlockPassNode;
import org.jruby.ast.BreakNode;
import org.jruby.ast.CallNode;
import org.jruby.ast.CaseNode;
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.Colon3Node;
import org.jruby.ast.ConstDeclNode;
import org.jruby.ast.ConstNode;
import org.jruby.ast.DAsgnNode;
import org.jruby.ast.DRegexpNode;
import org.jruby.ast.DStrNode;
import org.jruby.ast.DSymbolNode;
import org.jruby.ast.DVarNode;
import org.jruby.ast.DXStrNode;
import org.jruby.ast.DefinedNode;
import org.jruby.ast.DefnNode;
import org.jruby.ast.DefsNode;
import org.jruby.ast.DotNode;
import org.jruby.ast.EnsureNode;
import org.jruby.ast.EvStrNode;
import org.jruby.ast.FCallNode;
import org.jruby.ast.FalseNode;
import org.jruby.ast.FixnumNode;
import org.jruby.ast.FlipNode;
import org.jruby.ast.FloatNode;
import org.jruby.ast.ForNode;
import org.jruby.ast.GlobalAsgnNode;
import org.jruby.ast.GlobalVarNode;
import org.jruby.ast.HashNode;
import org.jruby.ast.IfNode;
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.Match2Node;
import org.jruby.ast.Match3Node;
import org.jruby.ast.MatchNode;
import org.jruby.ast.ModuleNode;
import org.jruby.ast.MultipleAsgnNode;
import org.jruby.ast.NewlineNode;
import org.jruby.ast.NextNode;
import org.jruby.ast.NilNode;
import org.jruby.ast.Node;
import org.jruby.ast.NotNode;
import org.jruby.ast.NthRefNode;
import org.jruby.ast.OpAsgnAndNode;
import org.jruby.ast.OpAsgnNode;
import org.jruby.ast.OpAsgnOrNode;
import org.jruby.ast.OpElementAsgnNode;
import org.jruby.ast.OptNNode;
import org.jruby.ast.OrNode;
import org.jruby.ast.PostExeNode;
import org.jruby.ast.RedoNode;
import org.jruby.ast.RegexpNode;
import org.jruby.ast.RescueBodyNode;
import org.jruby.ast.RescueNode;
import org.jruby.ast.RetryNode;
import org.jruby.ast.ReturnNode;
import org.jruby.ast.RootNode;
import org.jruby.ast.SClassNode;
import org.jruby.ast.SValueNode;
import org.jruby.ast.SelfNode;
import org.jruby.ast.SplatNode;
import org.jruby.ast.StrNode;
import org.jruby.ast.SuperNode;
import org.jruby.ast.SymbolNode;
import org.jruby.ast.ToAryNode;
import org.jruby.ast.TrueNode;
import org.jruby.ast.UndefNode;
import org.jruby.ast.UntilNode;
import org.jruby.ast.VAliasNode;
import org.jruby.ast.VCallNode;
import org.jruby.ast.WhenNode;
import org.jruby.ast.WhileNode;
import org.jruby.ast.XStrNode;
import org.jruby.ast.YieldNode;
import org.jruby.ast.ZArrayNode;
import org.jruby.ast.ZSuperNode;
import org.jruby.ast.visitor.NodeVisitor;
import org.jruby.evaluator.Instruction;
import org.jruby.lexer.yacc.ISourcePosition;
import org.jruby.lexer.yacc.SourcePosition;
import org.jruby.runtime.Arity;
import org.jruby.runtime.Visibility;
/**
* RubyASTBuildVisitor performs transformation from JRuby's AST to DLTK AST.
*/
public class RubyASTBuildVisitor implements NodeVisitor {
protected static final boolean TRACE_RECOVERING = Boolean
.valueOf(
Platform
.getDebugOption("org.eclipse.dltk.ruby.core/parsing/traceRecoveryWhenInterpretingAST")) //$NON-NLS-1$
.booleanValue();
private ModuleDeclaration module;
private final char[] content;
protected static interface IState {
public void add(ASTNode node);
}
protected static String getShortClassName(Object instance) {
final String className = instance.getClass().getName();
int dotIndex = className.lastIndexOf('.');
int dollarIndex = className.lastIndexOf('$');
if (dotIndex >= 0 || dollarIndex >= 0) {
return className.substring(Math.max(dotIndex, dollarIndex) + 1);
} else {
return className;
}
}
protected static class CollectingState implements IState {
private final ArrayList<ASTNode> list;
public CollectingState() {
list = new ArrayList<ASTNode>();
}
@Override
public void add(ASTNode s) {
list.add(s);
}
public ArrayList<ASTNode> getList() {
return list;
}
public void reset() {
list.clear();
}
@Override
public String toString() {
return getShortClassName(this) + '[' + list + ']';
}
}
protected static class ArgumentsState implements IState {
private final RubyCallArgumentsList list;
public ArgumentsState(RubyCallArgumentsList list) {
this.list = list;
}
@Override
public void add(ASTNode s) {
list.addArgument(s, 0);
}
@Override
public String toString() {
return getShortClassName(this) + '[' + list + ']';
}
}
protected static class TopLevelState implements IState {
private final ModuleDeclaration module;
public TopLevelState(ModuleDeclaration module) {
this.module = module;
}
@Override
public void add(ASTNode statement) {
module.getStatements().add(statement);
}
@Override
public String toString() {
return getShortClassName(this);
}
}
protected static abstract class ClassLikeState implements IState {
public int visibility;
public final TypeDeclaration type;
public final String fullName;
public ClassLikeState(TypeDeclaration type, String parentName) {
this.type = type;
this.fullName = parentName.length() == 0 ? type.getName()
: parentName + "::" + type.getName(); //$NON-NLS-1$
visibility = Modifiers.AccPublic;
}
@Override
public void add(ASTNode statement) {
type.getStatements().add(statement);
}
@Override
public String toString() {
return getShortClassName(this) + '[' + fullName + ']';
}
}
protected static class ClassState extends ClassLikeState {
public ClassState(TypeDeclaration type, String parentName) {
super(type, parentName);
}
}
protected static class ModuleState extends ClassLikeState {
public ModuleState(TypeDeclaration type, String parentName) {
super(type, parentName);
}
}
protected static class MethodState implements IState {
private final MethodDeclaration method;
public MethodState(MethodDeclaration method) {
this.method = method;
}
@Override
public void add(ASTNode statement) {
method.getStatements().add(statement);
}
@Override
public String toString() {
return getShortClassName(this) + '[' + method.getName() + ']';
}
}
protected static class BlockState implements IState {
public final Block block;
public BlockState(Block block) {
this.block = block;
}
@Override
public void add(ASTNode statement) {
block.getStatements().add(statement);
}
@Override
public String toString() {
return getShortClassName(this);
}
}
private static class StateManager {
private LinkedList<IState> states = new LinkedList<IState>();
public IState peek() {
return states.getLast();
}
public void pop() {
states.removeLast();
}
public void push(IState state) {
states.add(state);
}
public boolean isClassLikeState() {
IState state = peek();
if (state instanceof ClassLikeState) {
return true;
} else if (states.size() > 1) {
ListIterator<IState> i = states.listIterator(states.size());
while (i.hasPrevious()) {
IState s = i.previous();
if (s instanceof ClassLikeState) {
return true;
}
}
}
return false;
}
public ClassLikeState getClassLikeState() {
IState state = peek();
if (state instanceof ClassLikeState) {
return (ClassLikeState) state;
} else if (states.size() > 1) {
final ListIterator<IState> i = states.listIterator(states.size());
while (i.hasPrevious()) {
final IState s = i.previous();
if (s instanceof ClassLikeState) {
return (ClassLikeState) s;
}
}
}
return null;
}
public String getFullClassName() {
final ClassLikeState classState = getClassLikeState();
if (classState != null) {
return classState.fullName;
} else {
return Util.EMPTY_STRING;
}
}
}
private StateManager states = new StateManager();
protected ASTNode collectSingleNodeSafe(Node pathNode) {
return collectSingleNodeSafe(pathNode, false);
}
/**
* Safe wrapper for <code>collectSingleStatement0</code>. It checks
* SILENT_MODE flag, and it is true, just performs
* <code>node.accept(this);</code> without throwing an exception.
*
* @param node
* @param allowZero
* @return
*/
protected ASTNode collectSingleNodeSafe(Node node, boolean allowZero) {
ASTNode res = null;
try {
res = collectSingleNode0(node, allowZero);
} catch (Throwable t) {
if (JRubySourceParser.isSilentState()) {
node.accept(this);
} else {
throw new RuntimeException(t);
}
}
return res;
}
/**
* Tries to convert single JRuby's node to single DLTK AST node. If
* conversion fails, and for ex., more than one or zero nodes were fetched
* as result, then RuntimeException will be thrown. Option
* <code>allowZero</code> allows to fetch no DLTK nodes and just return null
* without throwing an exception.
*
* @param node
* @param allowZero
* @return
*/
protected ASTNode collectSingleNode0(Node node, boolean allowZero) {
if (node == null)
return null;
CollectingState state = new CollectingState();
states.push(state);
node.accept(this);
states.pop();
ArrayList<ASTNode> list = state.getList();
if (list.size() == 1)
return list.iterator().next();
if (node instanceof NewlineNode) {
NewlineNode newlineNode = (NewlineNode) node;
node = newlineNode.getNextNode();
}
if (list.size() > 1) {
throw new RuntimeException(
NLS.bind(
Messages.RubyASTBuildVisitor_jrubyNodeHasntBeenConvertedIntoAnyDltkAstNode,
node.getClass().getName()));
}
if (allowZero)
return null;
throw new RuntimeException(
NLS.bind(
Messages.RubyASTBuildVisitor_jrubyNodeHasntBeenConvertedIntoAnyDltkAstNode,
node.getClass().getName()));
}
protected char[] getContent() {
return content;
}
public RubyASTBuildVisitor(ModuleDeclaration module, char[] content) {
this.module = module;
this.content = content;
states.push(new TopLevelState(this.module));
}
@Override
public Instruction visitAliasNode(AliasNode iVisited) { // done
ISourcePosition pos = iVisited.getPosition();
final int start = pos.getStartOffset();
int end = pos.getEndOffset();
while (end > start && Character.isWhitespace(content[end - 1])) {
--end;
}
RubyAliasExpression expr = new RubyAliasExpression(start, end, iVisited
.getOldName(), iVisited.getNewName());
states.peek().add(expr);
return null;
}
@Override
public Instruction visitAndNode(AndNode iVisited) { // done
ASTNode left = collectSingleNodeSafe(iVisited.getFirstNode());
ASTNode right = collectSingleNodeSafe(iVisited.getSecondNode());
RubyBinaryExpression b = new RubyBinaryExpression(left,
ExpressionConstants.E_BAND, right);
states.peek().add(b);
return null;
}
// should never get here
@Override
public Instruction visitArgsNode(ArgsNode iVisited) {
if (iVisited.getOptArgs() != null) {
iVisited.getOptArgs().accept(this);
}
return null;
}
// should never get here
@Override
public Instruction visitArgsCatNode(ArgsCatNode iVisited) {
if (iVisited.getFirstNode() != null) {
iVisited.getFirstNode().accept(this);
}
if (iVisited.getSecondNode() != null) {
iVisited.getSecondNode().accept(this);
}
return null;
}
private List<ASTNode> processListNode(ListNode node) { // done
CollectingState coll = new CollectingState();
states.push(coll);
Iterator<Node> iterator = node.childNodes().iterator();
while (iterator.hasNext()) {
iterator.next().accept(this);
}
states.pop();
return coll.getList();
}
@Override
public Instruction visitArrayNode(ArrayNode iVisited) { // done
List<ASTNode> exprs = processListNode(iVisited);
ISourcePosition position = iVisited.getPosition();
RubyArrayExpression arr = new RubyArrayExpression();
arr.setEnd(position.getEndOffset());
arr.setStart(position.getStartOffset());
arr.setChilds(exprs);
states.peek().add(arr);
return null;
}
@Override
public Instruction visitBackRefNode(BackRefNode iVisited) { // done
ISourcePosition pos = iVisited.getPosition();
VariableReference ref = new VariableReference(pos.getStartOffset(), pos
.getEndOffset(), "$" + iVisited.getType()); //$NON-NLS-1$
states.peek().add(ref);
return null;
}
@Override
public Instruction visitBeginNode(BeginNode iVisited) { // done
ASTNode body = collectSingleNodeSafe(iVisited.getBodyNode());
ISourcePosition pos = iVisited.getPosition();
RubyBeginExpression e = new RubyBeginExpression(pos.getStartOffset(),
pos.getEndOffset(), body);
states.peek().add(e);
return null;
}
// should never get here
@Override
public Instruction visitBlockArgNode(BlockArgNode iVisited) {
return null;
}
@Override
public Instruction visitBlockNode(BlockNode iVisited) { // done
ISourcePosition pos = iVisited.getPosition();
Block block = new Block(pos.getStartOffset(), pos.getEndOffset());
states.push(new BlockState(block));
Iterator<Node> iterator = iVisited.childNodes().iterator();
while (iterator.hasNext()) {
iterator.next().accept(this);
}
states.pop();
states.peek().add(block);
return null;
}
@Override
public Instruction visitBlockPassNode(BlockPassNode iVisited) {
// ASTNode args = collectSingleNodeSafe(iVisited.getArgsNode());
ASTNode body = collectSingleNodeSafe(iVisited.getBodyNode());
ISourcePosition pos = iVisited.getPosition();
RubyBlock e = new RubyBlock(pos.getStartOffset(), pos.getEndOffset(),
body);
// TODO: handle vars
states.peek().add(e);
return null;
}
@Override
public Instruction visitBreakNode(BreakNode iVisited) { // done
ASTNode value = collectSingleNodeSafe(iVisited.getValueNode());
ISourcePosition pos = iVisited.getPosition();
RubyBreakExpression e = new RubyBreakExpression(pos.getStartOffset(),
pos.getEndOffset(), value);
states.peek().add(e);
return null;
}
@Override
public Instruction visitConstDeclNode(ConstDeclNode iVisited) {
Node pathNode = iVisited.getConstNode();
ASTNode pathResult = null;
if (pathNode != null)
pathResult = collectSingleNodeSafe(pathNode);
ASTNode value = collectSingleNodeSafe(iVisited.getValueNode());
ISourcePosition position = iVisited.getPosition();
int start = position.getStartOffset();
int end = start;
while (RubySyntaxUtils.isWhitespace(content[end])) {
end++;
}
while (RubySyntaxUtils.isNameChar(content[end])) {
end++;
}
SimpleReference name = new SimpleReference(start, end, iVisited
.getName());
RubyConstantDeclaration node = new RubyConstantDeclaration(position
.getStartOffset(), position.getEndOffset(), pathResult, name,
value);
states.peek().add(node);
return null;
}
@Override
public Instruction visitClassVarAsgnNode(ClassVarAsgnNode iVisited) {
processVariableAssignment(iVisited, iVisited.getName(),
RubyVariableKind.CLASS, iVisited.getValueNode());
return null;
}
@Override
public Instruction visitClassVarDeclNode(ClassVarDeclNode iVisited) {
processVariableAssignment(iVisited, iVisited.getName(),
RubyVariableKind.CLASS, iVisited.getValueNode());
return null;
}
@Override
public Instruction visitClassVarNode(ClassVarNode iVisited) {
processVariableReference(iVisited, iVisited.getName(),
RubyVariableKind.CLASS);
return null;
}
private void fixCallOffsets(CallExpression callNode, String nameNode,
int possibleDotPosition, int firstArgStart, int lastArgEnd) {
int dotPosition = RubySyntaxUtils.skipWhitespaceForward(content,
possibleDotPosition);
if (dotPosition >= 0 && dotPosition < content.length
&& content[dotPosition] == ']')
dotPosition++;
if (dotPosition >= 0 && dotPosition < content.length
&& (content[dotPosition] == '.' || content[dotPosition] == ':')) {
if (content[dotPosition] == ':')
dotPosition++;
fixFunctionCallOffsets(callNode, nameNode, dotPosition + 1,
firstArgStart, lastArgEnd);
return;
}
String methodName = nameNode;
if (methodName == RubySyntaxUtils.ARRAY_GET_METHOD) {
// TODO
} else if (methodName == RubySyntaxUtils.ARRAY_PUT_METHOD) {
// TODO
} else {
// WTF?
if (TRACE_RECOVERING)
RubyPlugin
.log("Ruby AST: non-dot-call not recognized, non-dot found at " //$NON-NLS-1$
+ dotPosition + ", function name " + methodName); //$NON-NLS-1$
}
// trim end whitespaces
int sourceEnd = callNode.sourceEnd() - 1;
while (sourceEnd >= 0 && Character.isWhitespace(content[sourceEnd]))
sourceEnd--;
if (sourceEnd >= 0)
callNode.setEnd(sourceEnd + 1);
}
private void fixFunctionCallOffsets(CallExpression callNode,
String methodName, int possibleNameStart, int firstArgStart,
int lastArgEnd) {
int nameStart = RubySyntaxUtils.skipWhitespaceForward(content,
possibleNameStart);
int nameEnd = nameStart + methodName.length();
// Assert.isLegal(nameSequence.toString().equals(methodName)); //XXX
callNode.getCallName().setStart(nameStart);
callNode.getCallName().setEnd(nameEnd);
if (firstArgStart < 0) {
int lParenOffset = RubySyntaxUtils.skipWhitespaceForward(content,
nameEnd);
if (lParenOffset >= 0 && content[lParenOffset] == '(') {
int rParenOffset = RubySyntaxUtils.skipWhitespaceForward(
content, lParenOffset + 1);
if (rParenOffset >= 0 && content[rParenOffset] == ')')
callNode.setEnd(rParenOffset + 1);
else {
if (TRACE_RECOVERING)
RubyPlugin
.log("Ruby AST: function call, empty args, no closing paren; " //$NON-NLS-1$
+ "opening paren at " //$NON-NLS-1$
+ lParenOffset
+ ", function name " + methodName); //$NON-NLS-1$
callNode.setEnd(lParenOffset - 1); // don't include these
// parens
}
}
} else {
if (nameEnd > firstArgStart) {
if (callNode.getArgs().getChilds().isEmpty()) {
callNode.setEnd(nameEnd);
}
if (TRACE_RECOVERING)
RubyPlugin
.log("DLTKASTBuildVisitor.fixFunctionCallOffsets(" //$NON-NLS-1$
+ methodName + "): nameEnd > firstArgStart"); //$NON-NLS-1$
return;
}
int lParenOffset = RubySyntaxUtils.skipWhitespaceForward(content,
nameEnd, firstArgStart);
if (lParenOffset >= 0 && content[lParenOffset] == '(') {
if (lastArgEnd <= lParenOffset) {
if (TRACE_RECOVERING)
RubyPlugin
.log("DLTKASTBuildVisitor.fixFunctionCallOffsets(" //$NON-NLS-1$
+ methodName
+ "): lastArgEnd <= lParenOffset"); //$NON-NLS-1$
return;
}
int rParenOffset = RubySyntaxUtils.skipWhitespaceForward(
content, lastArgEnd);
if (rParenOffset >= 0 && content[rParenOffset] == ')')
callNode.setEnd(rParenOffset + 1);
else {
if (TRACE_RECOVERING)
RubyPlugin
.log("Ruby AST: function call, non-empty args, no closing paren; " //$NON-NLS-1$
+ "opening paren at " //$NON-NLS-1$
+ lParenOffset + ", " //$NON-NLS-1$
+ "last argument ending at " //$NON-NLS-1$
+ lastArgEnd + ", function name " //$NON-NLS-1$
+ methodName);
callNode.setEnd(lastArgEnd); // probably no closing paren
}
}
}
if (lastArgEnd >= 0 && callNode.sourceEnd() < lastArgEnd)
callNode.setEnd(lastArgEnd);
}
/**
* @fixme iteration not correctly defined
*/
@Override
public Instruction visitCallNode(CallNode iVisited) {
String methodName = iVisited.getName();
CollectingState collector = new CollectingState();
Assert.isTrue(iVisited.getReceiverNode() != null);
states.push(collector);
iVisited.getReceiverNode().accept(this);
states.pop();
// TODO: uncomment when visitor is done
if (collector.getList().size() > 1) {
if (TRACE_RECOVERING)
RubyPlugin.log("DLTKASTBuildVisitor.visitCallNode(" //$NON-NLS-1$
+ methodName
+ "): receiver " //$NON-NLS-1$
+ iVisited.getReceiverNode().getClass().getName()
+ " turned into multiple nodes"); //$NON-NLS-1$
}
ASTNode recv;
if (collector.getList().size() < 1) {
recv = new NumericLiteral(-1, -1, 0);
recv.setStart(iVisited.getPosition().getStartOffset());
recv.setEnd(iVisited.getPosition().getEndOffset() + 1);
} else
recv = collector.getList().get(0);
collector.reset();
int argsStart = -1, argsEnd = -1;
RubyCallArgumentsList argList = new RubyCallArgumentsList();
Node argsNode = iVisited.getArgsNode();
if (argsNode != null) {
argList.setStart(argsNode.getPosition().getStartOffset());
argList.setEnd(argsNode.getPosition().getEndOffset());
states.push(new ArgumentsState(argList));
if (argsNode instanceof ListNode) {
ListNode arrayNode = (ListNode) argsNode;
List<Node> list = arrayNode.childNodes();
for (Iterator<Node> iter = list.iterator(); iter.hasNext();) {
Node node = iter.next();
node.accept(this);
}
} else {
if (TRACE_RECOVERING)
RubyPlugin.log("DLTKASTBuildVisitor.visitCallNode(" //$NON-NLS-1$
+ methodName + ") - unknown args node type: " //$NON-NLS-1$
+ argsNode.getClass().getName());
argsNode.accept(this);
}
states.pop();
List<Node> children = argsNode.childNodes();
if (children.size() > 0) {
argsStart = children.get(0).getPosition()
.getStartOffset();
argsEnd = children.get(children.size() - 1)
.getPosition().getEndOffset();
// correction for nodes with incorrect positions
List<ASTNode> argListExprs = argList.getChilds();
if (!argListExprs.isEmpty())
argsEnd = Math.max(argsEnd, argListExprs
.get(argListExprs.size() - 1).sourceEnd());
}
}
if (iVisited.getIterNode() != null) {
ASTNode s = collectSingleNodeSafe(iVisited.getIterNode());
argList.addNode(s);
}
argList.autosetOffsets();
CallExpression c = new CallExpression(recv, methodName, argList);
int receiverEnd = recv.sourceEnd();
c.setStart(iVisited.getPosition().getStartOffset());
c
.setEnd(argsEnd >= 0 ? argsEnd : iVisited.getPosition()
.getEndOffset()); // just in case, should
// be overriden
fixCallOffsets(c, methodName, receiverEnd, argsStart, argsEnd);
this.states.peek().add(c);
return null;
}
@Override
public Instruction visitCaseNode(CaseNode iVisited) { // done
ISourcePosition pos = iVisited.getPosition();
RubyCaseStatement statement = new RubyCaseStatement(pos
.getStartOffset(), pos.getEndOffset());
ASTNode caseTarget = collectSingleNodeSafe(iVisited.getCaseNode());
statement.setTarget(caseTarget);
Node caseBody = iVisited.getFirstWhenNode();
ASTNode caseSt = collectSingleNodeSafe(caseBody);
List whens = new ArrayList(1);
while (caseBody instanceof WhenNode) {
WhenNode whenNode = (WhenNode) caseBody;
whens.add(caseSt);
caseBody = whenNode.getNextCase();
caseSt = collectSingleNodeSafe(caseBody);
}
statement.setWhens(whens);
if (caseSt != null) {
statement.setElseWhen(caseSt);
}
states.peek().add(statement);
return null;
}
private static String colons2Name(Node cpathNode) {
String name = ""; //$NON-NLS-1$
while (cpathNode instanceof Colon2Node) {
Colon2Node colon2Node = (Colon2Node) cpathNode;
if (name.length() > 0)
name = "::" + name; //$NON-NLS-1$
name = colon2Node.getName() + name;
cpathNode = colon2Node.getLeftNode();
}
if (cpathNode instanceof Colon3Node) {
Colon3Node colon3Node = (Colon3Node) cpathNode;
if (name.length() > 0)
name = "::" + name; //$NON-NLS-1$
name = "::" + colon3Node.getName() + name; //$NON-NLS-1$
} else if (cpathNode instanceof ConstNode) {
ConstNode constNode = (ConstNode) cpathNode;
if (name.length() > 0)
name = "::" + name; //$NON-NLS-1$
name = constNode.getName() + name;
}
return name;
}
private ISourcePosition fixNamePosition(ISourcePosition pos) {
int start = pos.getStartOffset();
int end = pos.getEndOffset();
while (end - 1 >= 0 && (end - 1) > start
&& !RubySyntaxUtils.isNameChar(content[end - 1])) {
end--;
}
if (end >= 0) {
while (end < content.length
&& RubySyntaxUtils.isNameChar(content[end]))
end++;
}
return new SourcePosition(pos.getFile(), pos.getStartLine(), pos
.getEndLine(), start, end);
}
private ISourcePosition fixBorders(ISourcePosition pos) {
int start = pos.getStartOffset();
int end = pos.getEndOffset();
while (end - 1 >= 0 && !RubySyntaxUtils.isNameChar(content[end - 1])) {
end--;
}
if (end >= 0) {
while (end < content.length
&& RubySyntaxUtils.isNameChar(content[end]))
end++;
}
return new SourcePosition(pos.getFile(), pos.getStartLine(), pos
.getEndLine(), start, end);
}
@Override
public Instruction visitClassNode(ClassNode iVisited) {
Node cpathNode = iVisited.getCPath();
Node superClassNode = iVisited.getSuperNode();
ASTNode cpath = collectSingleNodeSafe(cpathNode);
ASTNode supernode = collectSingleNodeSafe(superClassNode);
ISourcePosition pos = iVisited.getCPath().getPosition();
ISourcePosition cPos = iVisited.getPosition();
cPos = fixNamePosition(cPos);
pos = fixNamePosition(pos);
RubyClassDeclaration type = new RubyClassDeclaration(supernode, cpath,
null, cPos.getStartOffset(), cPos.getEndOffset());
String name = colons2Name(cpathNode);
type.setName(name);
states.peek().add(type);
final String enclosingTypeName = states.getFullClassName();
type.setEnclosingTypeName(enclosingTypeName);
states.push(new ClassState(type, enclosingTypeName));
// body
Node bodyNode = iVisited.getBodyNode();
if (bodyNode != null) {
pos = bodyNode.getPosition();
int end = -1;
while (bodyNode instanceof NewlineNode)
bodyNode = ((NewlineNode) bodyNode).getNextNode();
if (bodyNode instanceof BlockNode) {
BlockNode blockNode = (BlockNode) bodyNode;
// XXX !!!!
end = blockNode.getLast().getPosition().getEndOffset() + 1;
}
pos = fixBorders(pos);
Block bl = new Block(pos.getStartOffset(), (end == -1) ? pos
.getEndOffset() + 1 : end);
type.setBody(bl);
if (bodyNode instanceof BlockNode) {
for (Iterator<Node> iterator = bodyNode.childNodes().iterator(); iterator
.hasNext();) {
Node n = iterator.next();
n.accept(this);
}
} else
bodyNode.accept(this);
}
states.pop();
return null;
}
@Override
public Instruction visitColon2Node(Colon2Node iVisited) {
CollectingState collector = new CollectingState();
states.push(collector);
if (iVisited.getLeftNode() != null) {
iVisited.getLeftNode().accept(this);
}
states.pop();
int start = iVisited.getPosition().getStartOffset();
int end = iVisited.getPosition().getEndOffset();
ASTNode left = null;
if (collector.list.size() == 1) {
left = collector.list.get(0);
}
String right = iVisited.getName();
if (left != null) {
RubyColonExpression colon = new RubyColonExpression(right, left);
colon.setStart(start);
colon.setEnd(end);
states.peek().add(colon);
} else {
ConstantReference ref = new ConstantReference(start, end, right);
states.peek().add(ref);
}
return null;
}
@Override
public Instruction visitColon3Node(Colon3Node iVisited) {
ISourcePosition position = iVisited.getPosition();
RubyColonExpression colon = new RubyColonExpression(iVisited.getName(),
null);
colon.setStart(position.getStartOffset());
colon.setEnd(position.getEndOffset());
states.peek().add(colon);
return null;
}
@Override
public Instruction visitConstNode(ConstNode iVisited) {
String name = iVisited.getName();
ISourcePosition pos = iVisited.getPosition();
pos = fixBorders(pos);
this.states.peek().add(
new ConstantReference(pos.getStartOffset(), pos.getEndOffset(),
name));
return null;
}
@Override
public Instruction visitDAsgnNode(DAsgnNode iVisited) {
ISourcePosition pos = iVisited.getPosition();
ASTNode valueNode = this.collectSingleNodeSafe(iVisited.getValueNode(),
true);
RubyDAssgnExpression e = new RubyDAssgnExpression(pos.getStartOffset(),
pos.getEndOffset(), iVisited.getName(), valueNode);
states.peek().add(e);
return null;
}
@Override
public Instruction visitDRegxNode(DRegexpNode iVisited) { // done
ISourcePosition pos = iVisited.getPosition();
List<ASTNode> list = processListNode(iVisited);
RubyDRegexpExpression ex = new RubyDRegexpExpression(pos
.getStartOffset(), pos.getEndOffset());
ex.setChilds(list);
states.peek().add(ex);
return null;
}
@Override
public Instruction visitDStrNode(DStrNode iVisited) { // done
ISourcePosition pos = iVisited.getPosition();
List<ASTNode> list = processListNode(iVisited);
RubyDynamicStringExpression ex = new RubyDynamicStringExpression(pos
.getStartOffset(), pos.getEndOffset());
ex.setChilds(list);
states.peek().add(ex);
return null;
}
/**
* @see NodeVisitor#visitDSymbolNode(DSymbolNode)
*/
@Override
public Instruction visitDSymbolNode(DSymbolNode iVisited) { // done
ISourcePosition pos = iVisited.getPosition();
List<ASTNode> list = processListNode(iVisited);
RubyDSymbolExpression ex = new RubyDSymbolExpression(pos
.getStartOffset(), pos.getEndOffset());
ex.setChilds(list);
states.peek().add(ex);
return null;
}
@Override
public Instruction visitDVarNode(DVarNode iVisited) { // done (?)
String name = iVisited.getName();
ISourcePosition pos = iVisited.getPosition();
RubyDVarExpression e = new RubyDVarExpression(pos.getStartOffset(), pos
.getEndOffset(), name);
states.peek().add(e);
return null;
}
@Override
public Instruction visitDXStrNode(DXStrNode iVisited) { // done
ISourcePosition pos = iVisited.getPosition();
List<ASTNode> list = processListNode(iVisited);
RubyDynamicBackquoteStringExpression ex = new RubyDynamicBackquoteStringExpression(
pos.getStartOffset(), pos.getEndOffset());
ex.setChilds(list);
states.peek().add(ex);
return null;
}
@Override
public Instruction visitDefinedNode(DefinedNode iVisited) { // done
ISourcePosition pos = iVisited.getPosition();
ASTNode value = collectSingleNodeSafe(iVisited.getExpressionNode());
RubyDefinedExpression e = new RubyDefinedExpression(pos
.getStartOffset(), pos.getEndOffset(), value);
states.peek().add(e);
return null;
}
private List<Argument> processMethodArguments(ArgsNode args) {
List<Argument> arguments = new ArrayList<Argument>();
Arity arity = args.getArity();
int endPos = args.getPosition().getStartOffset() - 1;
if (arity.getValue() != 0) { // BIG XXX, PLEASE CHECK IT
ListNode argsList = args.getArgs();
if (argsList != null) {
Iterator<Node> i = argsList.childNodes().iterator();
while (i.hasNext()) {
Node nde = i.next();
if (nde instanceof ArgumentNode) {
ArgumentNode a = (ArgumentNode) nde;
Argument aa = new RubyMethodArgument();
ISourcePosition argPos = fixNamePosition(a
.getPosition());
if (argPos.getEndOffset() > endPos)
endPos = argPos.getEndOffset();
aa.set(new SimpleReference(argPos.getStartOffset(),
argPos.getEndOffset(), a.getName()), null);
aa.setModifier(RubyMethodArgument.SIMPLE);
arguments.add(aa);
}
}
}
ListNode optArgs = args.getOptArgs();
if (optArgs != null) {
Iterator<?> iterator = optArgs.childNodes().iterator();
while (iterator.hasNext()) {
Object obj = iterator.next();
if (obj instanceof LocalAsgnNode) {
LocalAsgnNode a = (LocalAsgnNode) obj;
Argument aa = new RubyMethodArgument();
ISourcePosition argPos = a.getPosition();
if (argPos.getEndOffset() > endPos)
endPos = argPos.getEndOffset();
CollectingState coll = new CollectingState();
states.push(coll);
a.getValueNode().accept(this);
states.pop();
ASTNode defaultVal = null;
int nameStart = argPos.getStartOffset();
int nameEnd = argPos.getEndOffset();
if (coll.list.size() == 1) {
Object object = coll.list.get(0);
defaultVal = (ASTNode) object;
if (defaultVal.sourceStart() > nameStart
&& defaultVal.sourceStart() < nameEnd) {
nameEnd = defaultVal.sourceStart();
}
}
aa.set(new SimpleReference(nameStart, nameEnd, a
.getName()), defaultVal);
aa.setModifier(RubyMethodArgument.SIMPLE);
arguments.add(aa);
} else {
System.err
.println(Messages.RubyASTBuildVisitor_unknownArgumentType);
}
}
}
}
if (args.getRestArg() >= 0) {
// restore vararg name and position
int vaStart = 0, vaEnd = 0;
IState s = states.peek();
if (s instanceof MethodState) {
int bodyStart = args.getPosition().getEndOffset();
if (endPos >= 0 && endPos < bodyStart) { // this assumes that
// sourceStart is always set and always less than
// contents.length()
while (endPos < bodyStart && content[endPos] != '*')
endPos++;
endPos++;
if (endPos < content.length) {
vaStart = endPos - 1;
while (RubySyntaxUtils
.isIdentifierCharacter(content[endPos]))
endPos++;
vaEnd = endPos;
}
}
}
Argument aa = new RubyMethodArgument();
aa.set(new SimpleReference(vaStart + 1, vaEnd, String.copyValueOf(
content, vaStart, vaEnd - vaStart)), null);
aa.setModifier(RubyMethodArgument.VARARG);
arguments.add(aa);
}
BlockArgNode blockArgNode = args.getBlockArgNode();
if (blockArgNode != null) {
ISourcePosition position = fixNamePosition(blockArgNode
.getPosition());
String baName = String.copyValueOf(content, position
.getStartOffset() - 1, position.getEndOffset()
- (position.getStartOffset() - 1));
Argument aa = new RubyMethodArgument();
aa.set(new SimpleReference(position.getStartOffset(), position
.getEndOffset(), baName), null); // XXX:
aa.setModifier(RubyMethodArgument.BLOCK);
arguments.add(aa);
}
return arguments;
}
private void setMethodVisibility(MethodDeclaration method,
Visibility visibility) {
if (visibility.isPrivate())
ASTUtils.setVisibility(method, Modifiers.AccPrivate);
if (visibility.isPublic())
ASTUtils.setVisibility(method, Modifiers.AccPublic);
if (visibility.isProtected())
ASTUtils.setVisibility(method, Modifiers.AccProtected);
}
// method
@Override
public Instruction visitDefnNode(DefnNode iVisited) {
// Collection comments = iVisited.getComments();
// System.out.println(comments);
ArgumentNode nameNode = iVisited.getNameNode();
ISourcePosition pos = fixNamePosition(nameNode.getPosition());
ISourcePosition cPos = fixNamePosition(iVisited.getPosition());
MethodDeclaration method = new MethodDeclaration(iVisited.getName(),
pos.getStartOffset(), pos.getEndOffset(),
cPos.getStartOffset(), cPos.getEndOffset());
setMethodVisibility(method, iVisited.getVisibility());
if (states.isClassLikeState()) {
ClassLikeState classState = states.getClassLikeState();
ASTUtils.setVisibility(method, classState.visibility);
}
final ClassLikeState classState = states.getClassLikeState();
if (classState != null) {
method.setDeclaringTypeName(classState.fullName);
}
states.peek().add(method);
states.push(new MethodState(method));
Node bodyNode = iVisited.getBodyNode();
if (bodyNode != null) {
ISourcePosition bodyPos = bodyNode.getPosition();
method.getBody().setStart(bodyPos.getStartOffset());
method.getBody().setEnd(bodyPos.getEndOffset());
if (bodyNode instanceof BlockNode) {
for (Iterator<Node> iterator = bodyNode.childNodes().iterator(); iterator
.hasNext();) {
Node n = iterator.next();
n.accept(this);
}
} else
bodyNode.accept(this);
}
ArgsNode args = iVisited.getArgsNode();
if (args != null) {
List<Argument> arguments = processMethodArguments(args);
method.acceptArguments(arguments);
}
states.pop();
return null;
}
private ISourcePosition restoreMethodNamePosition(DefsNode node, int recvEnd) {
ISourcePosition recvPos = node.getReceiverNode().getPosition();
int pos = recvEnd;
if (pos >= 0) {
while (pos < content.length && content[pos] != '.'
&& content[pos] != ':')
pos++;
if (content[pos] == ':')
pos++;
}
if (pos >= content.length || pos < 0)
return recvPos;
int nameStart = RubySyntaxUtils.skipWhitespaceForward(content, pos + 1);
int nameEnd = nameStart;
while (RubySyntaxUtils.isIdentifierCharacter(content[nameEnd]))
nameEnd++;
return new SourcePosition(recvPos.getFile(), recvPos.getStartLine(),
recvPos.getEndLine(), nameStart, nameEnd);
}
// singleton method
@Override
public Instruction visitDefsNode(DefsNode iVisited) {
ASTNode receiverExpression = null;
Node receiverNode = iVisited.getReceiverNode();
CollectingState collectingState = new CollectingState();
states.push(collectingState);
receiverNode.accept(this);
states.pop();
if (collectingState.list.size() == 1) {
Object obj = collectingState.list.get(0);
receiverExpression = (ASTNode) obj;
}
ISourcePosition cPos = iVisited.getPosition();
// if (receiverExpression == null)
// System.out.println();
ISourcePosition namePos = restoreMethodNamePosition(iVisited,
receiverExpression.sourceEnd());
String name = iVisited.getName();
// if (receiverNode instanceof SelfNode) {
// name = "self." + name;
// } else if (receiverNode instanceof ConstNode) {
// name = ((ConstNode) receiverNode).getName() + "." + name;
// }
RubySingletonMethodDeclaration method = new RubySingletonMethodDeclaration(
name, namePos.getStartOffset(), namePos.getEndOffset(), cPos
.getStartOffset(), cPos.getEndOffset(),
receiverExpression);
method.setModifier(Modifiers.AccStatic);
ASTUtils.setVisibility(method, Modifiers.AccPublic);
// if (states.peek() instanceof ClassLikeState) {
if (states.isClassLikeState()) {
ClassLikeState classState = states.getClassLikeState();
ASTUtils.setVisibility(method, classState.visibility);
}
states.peek().add(method);
states.push(new MethodState(method));
ArgsNode args = iVisited.getArgsNode();
if (args != null) {
List list = processMethodArguments(args);
method.acceptArguments(list);
}
Node bodyNode = iVisited.getBodyNode();
if (bodyNode != null) {
if (bodyNode instanceof BlockNode) {
for (Iterator iterator = bodyNode.childNodes().iterator(); iterator
.hasNext();) {
Node n = (Node) iterator.next();
n.accept(this);
}
} else
bodyNode.accept(this);
}
states.pop();
return null;
}
@Override
public Instruction visitDotNode(DotNode iVisited) { // done
ASTNode begin = collectSingleNodeSafe(iVisited.getBeginNode());
ASTNode end = collectSingleNodeSafe(iVisited.getEndNode());
ISourcePosition pos = iVisited.getPosition();
RubyDotExpression e = new RubyDotExpression(pos.getStartOffset(), pos
.getEndOffset(), begin, end);
states.peek().add(e);
return null;
}
@Override
public Instruction visitEnsureNode(EnsureNode iVisited) { // done
ASTNode body = collectSingleNodeSafe(iVisited.getBodyNode());
ASTNode ensure = collectSingleNodeSafe(iVisited.getEnsureNode());
ISourcePosition pos = iVisited.getPosition();
RubyEnsureExpression e = new RubyEnsureExpression(pos.getStartOffset(),
pos.getEndOffset(), ensure, body);
states.peek().add(e);
return null;
}
@Override
public Instruction visitEvStrNode(EvStrNode iVisited) { // done
ISourcePosition pos = iVisited.getPosition();
ASTNode body = collectSingleNodeSafe(iVisited.getBody());
RubyEvaluatableStringExpression e = new RubyEvaluatableStringExpression(
pos.getStartOffset(), pos.getEndOffset(), body);
states.peek().add(e);
return null;
}
@Override
public Instruction visitFCallNode(FCallNode iVisited) {
String methodName = iVisited.getName();
if (states.isClassLikeState()) {
if (methodName.equals("private")) //$NON-NLS-1$
handleVisibilitySetter(iVisited, Modifiers.AccPrivate);
else if (methodName.equals("protected")) //$NON-NLS-1$
handleVisibilitySetter(iVisited, Modifiers.AccProtected);
else if (methodName.equals("public")) //$NON-NLS-1$
handleVisibilitySetter(iVisited, Modifiers.AccPublic);
}
RubyCallArgumentsList argList = new RubyCallArgumentsList();
Node argsNode = iVisited.getArgsNode();
if (argsNode != null) {
argList.setStart(argsNode.getPosition().getStartOffset());
argList.setEnd(argsNode.getPosition().getEndOffset());
states.push(new ArgumentsState(argList));
if (argsNode instanceof ListNode) {
ListNode arrayNode = (ListNode) argsNode;
List list = arrayNode.childNodes();
for (Iterator iter = list.iterator(); iter.hasNext();) {
Node node = (Node) iter.next();
node.accept(this);
}
} else {
if (TRACE_RECOVERING)
RubyPlugin.log("DLTKASTBuildVisitor.visitFCallNode(" //$NON-NLS-1$
+ methodName + ") - unknown args node type: " //$NON-NLS-1$
+ argsNode.getClass().getName());
argsNode.accept(this);
}
states.pop();
}
if (iVisited.getIterNode() != null) {
ASTNode s = collectSingleNodeSafe(iVisited.getIterNode());
argList.addNode(s);
}
argList.autosetOffsets();
CallExpression c = new CallExpression(null, methodName, argList);
int funcNameStart = iVisited.getPosition().getStartOffset();
c.setStart(funcNameStart);
c.setEnd(funcNameStart + methodName.length());
fixFunctionCallOffsets(c, methodName, funcNameStart, argList
.sourceStart(), argList.sourceEnd());
states.peek().add(c);
return null;
}
private void handleVisibilitySetter(FCallNode node, int newVisibility) {
if (states.isClassLikeState()) {
ClassLikeState classState = states.getClassLikeState();
Node argsNode = node.getArgsNode();
if (argsNode instanceof ArrayNode) {
ArrayNode argsArrayNode = (ArrayNode) argsNode;
List args = argsArrayNode.childNodes();
for (Iterator iter = args.iterator(); iter.hasNext();) {
Node arg = (Node) iter.next();
if (arg instanceof SymbolNode) {
SymbolNode symbolNode = (SymbolNode) arg;
String xmethodName = symbolNode.getName();
List statements = classState.type.getStatements();
for (Iterator statIter = statements.iterator(); statIter
.hasNext();) {
ASTNode statement = (ASTNode) statIter.next();
if (statement instanceof MethodDeclaration) {
MethodDeclaration methodDeclaration = (MethodDeclaration) statement;
if (methodDeclaration.getName().equals(
xmethodName))
ASTUtils.setVisibility(methodDeclaration,
newVisibility);
}
}
}
}
}
}
}
@Override
public Instruction visitFalseNode(FalseNode iVisited) { // done
ISourcePosition position = iVisited.getPosition();
states.peek().add(
new BooleanLiteral(position.getStartOffset(), position
.getEndOffset(), false));
return null;
}
@Override
public Instruction visitFlipNode(FlipNode iVisited) {
return null;
}
@Override
public Instruction visitForNode(ForNode iVisited) { // done
ASTNode varNode = collectSingleNodeSafe(iVisited.getVarNode());
ASTNode listSt = collectSingleNodeSafe(iVisited.getIterNode());
ASTNode listNode;
if (!(listSt instanceof org.eclipse.dltk.ast.ASTListNode)) {
org.eclipse.dltk.ast.ASTListNode list = new org.eclipse.dltk.ast.ASTListNode();
list.addNode(listSt);
listNode = list;
} else
listNode = listSt;
ASTNode bodyNode = collectSingleNodeSafe(iVisited.getBodyNode());
ISourcePosition pos = iVisited.getPosition();
RubyForStatement2 statement = new RubyForStatement2(pos
.getStartOffset(), pos.getEndOffset(), varNode,
(org.eclipse.dltk.ast.ASTListNode) listNode, bodyNode);
states.peek().add(statement);
return null;
}
@Override
public Instruction visitGlobalAsgnNode(GlobalAsgnNode iVisited) {
processVariableAssignment(iVisited, iVisited.getName(),
RubyVariableKind.GLOBAL, iVisited.getValueNode());
return null;
}
@Override
public Instruction visitGlobalVarNode(GlobalVarNode iVisited) {
processVariableReference(iVisited, iVisited.getName(),
RubyVariableKind.GLOBAL);
return null;
}
@Override
public Instruction visitHashNode(HashNode iVisited) { // done
ListNode listNode = iVisited.getListNode();
List<ASTNode> exprs = processListNode(listNode);
ISourcePosition position = iVisited.getPosition();
RubyHashExpression arr = new RubyHashExpression();
arr.setStart(position.getStartOffset());
arr.setEnd(position.getEndOffset());
if (arr.sourceEnd() == arr.sourceStart() && listNode != null) {
arr.setStart(listNode.getPosition().getStartOffset());
arr.setEnd(listNode.getPosition().getEndOffset());
}
List<ASTNode> hashPairs = new ArrayList<ASTNode>();
if (exprs.size() % 2 == 0) {
Iterator<ASTNode> i = exprs.iterator();
while (i.hasNext()) {
ASTNode key = i.next();
ASTNode value = i.next();
RubyHashPairExpression e = new RubyHashPairExpression(key
.sourceStart(), value.sourceEnd(), key, value);
hashPairs.add(e);
}
} else {
if (!JRubySourceParser.isSilentState()) {
throw new RuntimeException(
Messages.RubyASTBuildVisitor_unpairedHash);
}
}
arr.setChilds(hashPairs);
states.peek().add(arr);
return null;
}
@Override
public Instruction visitInstAsgnNode(InstAsgnNode iVisited) {
processVariableAssignment(iVisited, iVisited.getName(),
RubyVariableKind.INSTANCE, iVisited.getValueNode());
return null;
}
@Override
public Instruction visitInstVarNode(InstVarNode iVisited) {
processVariableReference(iVisited, iVisited.getName(),
RubyVariableKind.INSTANCE);
return null;
}
@Override
public Instruction visitIfNode(IfNode iVisited) { // done
ASTNode condition = collectSingleNodeSafe(iVisited.getCondition());
ASTNode thenPart = collectSingleNodeSafe(iVisited.getThenBody());
ASTNode elsePart = collectSingleNodeSafe(iVisited.getElseBody());
RubyIfStatement res = new RubyIfStatement(condition, thenPart, elsePart);
res.setStart(iVisited.getPosition().getStartOffset());
res.setEnd(iVisited.getPosition().getEndOffset() + 1);
states.peek().add(res);
return null;
}
@Override
public Instruction visitIterNode(IterNode iVisited) { // done
ASTNode bodyNode = collectSingleNodeSafe(iVisited.getBodyNode());
ASTNode varNode = collectSingleNodeSafe(iVisited.getVarNode());
ISourcePosition pos = iVisited.getPosition();
RubyBlock block = new RubyBlock(pos.getStartOffset(), pos
.getEndOffset(), bodyNode);
block.addVar(varNode);
states.peek().add(block);
return null;
}
@Override
public Instruction visitLocalAsgnNode(LocalAsgnNode iVisited) {
processVariableAssignment(iVisited, iVisited.getName(),
RubyVariableKind.LOCAL, iVisited.getValueNode());
return null;
}
private void processVariableAssignment(Node iVisited, String name,
RubyVariableKind varKind, Node valueNode) {
ISourcePosition pos = iVisited.getPosition();
ASTNode left = new VariableReference(pos.getStartOffset(), pos
.getStartOffset()
+ name.length(), name, varKind);
ASTNode right = collectSingleNodeSafe(valueNode);
RubyAssignment assgn = new RubyAssignment(left, right);
copyOffsets(assgn, iVisited);
states.peek().add(assgn);
}
@Override
public Instruction visitLocalVarNode(LocalVarNode iVisited) {
processVariableReference(iVisited, iVisited.getName(),
RubyVariableKind.LOCAL);
return null;
}
private void processVariableReference(Node iVisited, String varName,
RubyVariableKind varKind) {
final ISourcePosition pos = iVisited.getPosition();
final int start = pos.getStartOffset();
int end = pos.getEndOffset();
if (end - start > varName.length()) {
end = start + varName.length();
}
VariableReference node = new VariableReference(start, end, varName,
varKind);
states.peek().add(node);
}
private void copyOffsets(ASTNode target, Node source) {
ISourcePosition pos = source.getPosition();
target.setStart(pos.getStartOffset());
target.setEnd(pos.getEndOffset());
}
@Override
public Instruction visitMultipleAsgnNode(MultipleAsgnNode iVisited) { // done
ISourcePosition pos = iVisited.getPosition();
RubyMultipleAssignmentStatement s = new RubyMultipleAssignmentStatement(
pos.getStartOffset(), pos.getEndOffset());
ListNode headNode = iVisited.getHeadNode();
if (headNode != null) {
for (Iterator<Node> iterator = headNode.childNodes().iterator(); iterator
.hasNext();) {
Node n = iterator.next();
if (n instanceof LocalAsgnNode
&& ((LocalAsgnNode) n).getValueNode() == null) {
String name = ((LocalAsgnNode) n).getName();
ISourcePosition nPos = n.getPosition();
s.addLhs(new VariableReference(nPos.getStartOffset(), nPos
.getEndOffset(), name, RubyVariableKind.LOCAL));
} else {
ASTNode ss = collectSingleNodeSafe(n);
s.addLhs(ss);
}
}
}
Node argsNode = iVisited.getArgsNode();
if (argsNode != null) {
s.setLeftAsterix(collectSingleNodeSafe(argsNode), argsNode
.getPosition().getStartOffset());
}
Node valueNode = iVisited.getValueNode();
if (valueNode instanceof ArgsCatNode) {
ArgsCatNode argsCatNode = (ArgsCatNode) valueNode;
Node firstNode = argsCatNode.getFirstNode();
if (firstNode instanceof ListNode) {
ListNode list = (ListNode) firstNode;
for (Iterator<Node> iterator = list.childNodes().iterator(); iterator
.hasNext();) {
Node nd = iterator.next();
s.addRhs(collectSingleNodeSafe(nd));
}
} else if (firstNode != null)
s.addRhs(collectSingleNodeSafe(firstNode));
Node secondNode = argsCatNode.getSecondNode();
if (secondNode != null)
s.setRightAsterix(collectSingleNodeSafe(secondNode));
} else if (valueNode instanceof ListNode) {
ListNode list = (ListNode) valueNode;
for (Iterator<Node> iterator = list.childNodes().iterator(); iterator
.hasNext();) {
Node nd = iterator.next();
s.addRhs(collectSingleNodeSafe(nd));
}
} else if (valueNode != null) {
s.addRhs(collectSingleNodeSafe(valueNode));
}
states.peek().add(s);
return null;
}
@Override
public Instruction visitMatch2Node(Match2Node iVisited) {// done
ISourcePosition pos = iVisited.getPosition();
ASTNode receiverNode = collectSingleNodeSafe(iVisited.getReceiverNode());
ASTNode valueNode = collectSingleNodeSafe(iVisited.getValueNode());
RubyMatch2Expression e = new RubyMatch2Expression(pos.getStartOffset(),
pos.getEndOffset(), receiverNode, valueNode);
states.peek().add(e);
return null;
}
@Override
public Instruction visitMatch3Node(Match3Node iVisited) {// done
ISourcePosition pos = iVisited.getPosition();
ASTNode receiverNode = collectSingleNodeSafe(iVisited.getReceiverNode());
ASTNode valueNode = collectSingleNodeSafe(iVisited.getValueNode());
RubyMatch3Expression e = new RubyMatch3Expression(pos.getStartOffset(),
pos.getEndOffset(), receiverNode, valueNode);
states.peek().add(e);
return null;
}
@Override
public Instruction visitMatchNode(MatchNode iVisited) { // done
ISourcePosition pos = iVisited.getPosition();
ASTNode regexp = collectSingleNodeSafe(iVisited.getRegexpNode());
RubyMatchExpression e = new RubyMatchExpression(pos.getStartOffset(),
pos.getEndOffset(), regexp);
states.peek().add(e);
return null;
}
@Override
public Instruction visitModuleNode(ModuleNode iVisited) {
String name = ""; //$NON-NLS-1$
Node cpathNode = iVisited.getCPath();
if (cpathNode instanceof Colon2Node || cpathNode instanceof ConstNode) {
name = colons2Name(cpathNode);
}
ASTNode cpath = collectSingleNodeSafe(cpathNode);
ISourcePosition pos = iVisited.getCPath().getPosition();
ISourcePosition cPos = iVisited.getPosition();
cPos = fixNamePosition(cPos);
pos = fixNamePosition(pos);
RubyModuleDeclaration type = new RubyModuleDeclaration(cpath, null,
cPos.getStartOffset(), cPos.getEndOffset());
type.setModifier(Modifiers.AccModule);
states.peek().add(type);
final String enclosingTypeName = states.getFullClassName();
type.setEnclosingTypeName(enclosingTypeName);
states.push(new ModuleState(type, enclosingTypeName));
// body
Node bodyNode = iVisited.getBodyNode();
if (bodyNode != null) {
pos = bodyNode.getPosition();
int end = -1;
while (bodyNode instanceof NewlineNode)
bodyNode = ((NewlineNode) bodyNode).getNextNode();
if (bodyNode instanceof BlockNode) {
BlockNode blockNode = (BlockNode) bodyNode;
// XXX!!!!
end = blockNode.getLast().getPosition().getEndOffset();
} else {
if (TRACE_RECOVERING)
RubyPlugin.log("DLTKASTBuildVisitor.visitModuleNode(" //$NON-NLS-1$
+ name + "): unknown body type " //$NON-NLS-1$
+ bodyNode.getClass().getName());
}
pos = fixBorders(pos);
Block bl = new Block(pos.getStartOffset(), (end == -1) ? pos
.getEndOffset() : end);
type.setBody(bl);
bodyNode.accept(this);
}
states.pop();
return null;
}
@Override
public Instruction visitNewlineNode(NewlineNode iVisited) { // done
iVisited.getNextNode().accept(this);
return null;
}
@Override
public Instruction visitNextNode(NextNode iVisited) { // done
ISourcePosition position = iVisited.getPosition();
RubyCallArgumentsList args = new RubyCallArgumentsList();
Node valueNode = iVisited.getValueNode();
if (valueNode != null) {
ASTNode s = collectSingleNodeSafe(valueNode);
args.addArgument(s, 0);
}
states.peek().add(
new RubyNextExpression(position.getStartOffset(), position
.getEndOffset(), args));
return null;
}
@Override
public Instruction visitNilNode(NilNode iVisited) { // done
ISourcePosition pos = iVisited.getPosition();
states.peek().add(
new NilLiteral(pos.getStartOffset(), pos.getEndOffset()));
return null;
}
@Override
public Instruction visitNotNode(NotNode iVisited) { // done
ISourcePosition pos = iVisited.getPosition();
ASTNode expr = collectSingleNodeSafe(iVisited.getConditionNode());
RubyNotExpression e = new RubyNotExpression(pos.getStartOffset(), pos
.getEndOffset(), expr);
states.peek().add(e);
return null;
}
@Override
public Instruction visitNthRefNode(NthRefNode iVisited) { // done
ISourcePosition pos = iVisited.getPosition();
states.peek().add(
new VariableReference(pos.getStartOffset(), pos.getEndOffset(),
"$" + iVisited.getMatchNumber(), //$NON-NLS-1$
RubyVariableKind.GLOBAL));
return null;
}
@Override
public Instruction visitOpElementAsgnNode(OpElementAsgnNode iVisited) {
return null;
}
@Override
public Instruction visitOpAsgnNode(OpAsgnNode iVisited) {
return null;
}
@Override
public Instruction visitOpAsgnAndNode(OpAsgnAndNode iVisited) {
return null;
}
@Override
public Instruction visitOpAsgnOrNode(OpAsgnOrNode iVisited) {
return null;
}
@Override
public Instruction visitOptNNode(OptNNode iVisited) {
// System.out.println("DLTKASTBuildVisitor.visitOptNNode()");
iVisited.getBodyNode().accept(this);
return null;
}
@Override
public Instruction visitOrNode(OrNode iVisited) { // done
ASTNode leftSt = collectSingleNodeSafe(iVisited.getFirstNode());
ASTNode rightSt = collectSingleNodeSafe(iVisited.getSecondNode());
RubyBinaryExpression b = new RubyBinaryExpression(leftSt,
ExpressionConstants.E_BOR, rightSt);
states.peek().add(b);
return null;
}
@Override
public Instruction visitPostExeNode(PostExeNode iVisited) {
return null;
}
@Override
public Instruction visitRedoNode(RedoNode iVisited) {
ISourcePosition position = iVisited.getPosition();
states.peek().add(
new RubyRedoExpression(position.getStartOffset(), position
.getEndOffset()));
return null;
}
@Override
public Instruction visitRescueBodyNode(RescueBodyNode iVisited) { // done
ASTNode bodyNode = collectSingleNodeSafe(iVisited.getBodyNode());
ASTNode exceptionNodes = collectSingleNodeSafe(iVisited
.getExceptionNodes()); // in fact it would be an expression
// list
// TODO: exception nodes contains only names of exceptions, not their
// names itself
// so we need to parse them by hands
RubyRescueBodyStatement optRescueNode = (RubyRescueBodyStatement) collectSingleNodeSafe(iVisited
.getOptRescueNode());
ISourcePosition pos = iVisited.getPosition();
RubyRescueBodyStatement rescueStatement = new RubyRescueBodyStatement(
pos.getStartOffset(), pos.getEndOffset(), bodyNode,
exceptionNodes, optRescueNode);
states.peek().add(rescueStatement);
return null;
}
@Override
public Instruction visitRescueNode(RescueNode iVisited) { // done
ASTNode bodyNode = collectSingleNodeSafe(iVisited.getBodyNode());
ASTNode elseNode = collectSingleNodeSafe(iVisited.getElseNode());
RubyRescueBodyStatement rescueNode = (RubyRescueBodyStatement) collectSingleNodeSafe(iVisited
.getRescueNode());
ISourcePosition pos = iVisited.getPosition();
RubyRescueStatement rescueStatement = new RubyRescueStatement(pos
.getStartOffset(), pos.getEndOffset(), bodyNode, elseNode,
rescueNode);
states.peek().add(rescueStatement);
return null;
}
@Override
public Instruction visitRetryNode(RetryNode iVisited) { // done
ISourcePosition position = iVisited.getPosition();
states.peek().add(
new RubyRetryExpression(position.getStartOffset(), position
.getEndOffset()));
return null;
}
@Override
public Instruction visitReturnNode(ReturnNode iVisited) {
ISourcePosition position = iVisited.getPosition();
ASTNode value = null;
if (iVisited.getValueNode() != null) {
value = collectSingleNodeSafe(iVisited.getValueNode());
}
RubyCallArgumentsList list = new RubyCallArgumentsList();
if (value != null)
list.addArgument(value, 0);
states.peek().add(
new RubyReturnStatement(list, position.getStartOffset(),
position.getEndOffset()));
return null;
}
@Override
public Instruction visitSClassNode(SClassNode iVisited) {
String name = ""; //$NON-NLS-1$
Node receiver = iVisited.getReceiverNode();
if (receiver instanceof ConstNode) {
name = "<< " + ((ConstNode) iVisited.getReceiverNode()).getName(); //$NON-NLS-1$
} else if (receiver instanceof SelfNode) {
name = "<< self"; //$NON-NLS-1$
} else {
int startOffset = receiver.getPosition().getStartOffset();
int endOffset = receiver.getPosition().getEndOffset();
name = "<< " //$NON-NLS-1$
+ String.copyValueOf(content, startOffset,
endOffset - startOffset).trim();
}
ISourcePosition pos = iVisited.getReceiverNode().getPosition();
ISourcePosition cPos = iVisited.getPosition();
RubySingletonClassDeclaration type = new RubySingletonClassDeclaration(
name, pos.getStartOffset(), pos.getEndOffset(), cPos
.getStartOffset(), cPos.getEndOffset());
states.peek().add(type);
CollectingState coll = new CollectingState();
states.push(coll);
receiver.accept(this);
states.pop();
if (coll.list.size() == 1 && coll.list.get(0) instanceof ASTNode) {
Object obj = coll.list.get(0);
type.setReceiver((ASTNode) obj);
if (obj instanceof SimpleReference) {
SimpleReference reference = (SimpleReference) obj;
type.setName("<< " + reference.getName()); //$NON-NLS-1$
}
}
states.push(new ClassState(type, states.getFullClassName()));
Node bodyNode = iVisited.getBodyNode();
if (bodyNode != null) {
pos = bodyNode.getPosition();
Block bl = new Block(pos.getStartOffset(), pos.getEndOffset() + 1);
type.setBody(bl);
bodyNode.accept(this);
}
states.pop();
return null;
}
@Override
public Instruction visitSelfNode(SelfNode iVisited) {
ISourcePosition position = fixNamePosition(iVisited.getPosition());
states.peek().add(
new RubySelfReference(position.getStartOffset(), position
.getEndOffset()));
return null;
}
@Override
public Instruction visitSplatNode(SplatNode iVisited) {
Iterator<Node> iterator = iVisited.childNodes().iterator();
while (iterator.hasNext()) {
iterator.next().accept(this);
}
return null;
}
@Override
public Instruction visitStrNode(StrNode iVisited) {
String value = iVisited.getValue().toString();
ISourcePosition position = iVisited.getPosition();
int start = position.getStartOffset();
int end = position.getEndOffset();
if (value.length() == 0 && !isEmptyString(start, end)) {
// FIXME why do we need this code? only for the __FILE__?
value = String.copyValueOf(content, start, end - start);
} else {
value = '"' + value + '"';
}
states.peek().add(new StringLiteral(start, end, value));
return null;
}
private boolean isEmptyString(int start, int end) {
if (end - start == 2) {
if (content[start] == '\'' && content[start + 1] == '\''
|| content[start] == '"' && content[start + 1] == '"') {
return true;
}
} else if (end - start == 3) {
if (content[start] == '%') {
final char starter = content[start + 1];
if (!RubySyntaxUtils.isValidPercentStringStarter(starter)) {
final char terminator = RubySyntaxUtils
.getPercentStringTerminator(starter);
if (terminator != 0 && content[start + 2] == terminator) {
return true;
}
}
}
} else if (end - start == 4) {
if (content[start] == '%') {
if (RubySyntaxUtils
.isValidPercentStringStarter(content[start + 1])) {
final char terminator = RubySyntaxUtils
.getPercentStringTerminator(content[start + 2]);
if (terminator != 0 && content[start + 3] == terminator) {
return true;
}
}
}
}
return false;
}
@Override
public Instruction visitSValueNode(SValueNode iVisited) {
Iterator<Node> iterator = iVisited.childNodes().iterator();
while (iterator.hasNext()) {
iterator.next().accept(this);
}
return null;
}
private CallArgumentsList processCallArguments(Node argsNode) {
RubyCallArgumentsList argList = new RubyCallArgumentsList();
states.push(new ArgumentsState(argList));
if (argsNode instanceof ListNode) {
ListNode arrayNode = (ListNode) argsNode;
List<Node> list = arrayNode.childNodes();
for (Iterator<Node> iter = list.iterator(); iter.hasNext();) {
Node node = iter.next();
node.accept(this);
}
} else if (argsNode instanceof ArgsCatNode) {
ArgsCatNode argsCatNode = (ArgsCatNode) argsNode;
CallArgumentsList first = processCallArguments(argsCatNode
.getFirstNode());
CallArgumentsList second = processCallArguments(argsCatNode
.getSecondNode());
for (Iterator<ASTNode> iterator = first.getChilds().iterator(); iterator
.hasNext();) {
ASTNode e = iterator.next();
argList.addNode(e);
}
for (Iterator<ASTNode> iterator = second.getChilds().iterator(); iterator
.hasNext();) {
ASTNode e = iterator.next();
argList.addNode(e);
}
} else if (argsNode != null) {
argsNode.accept(this);
}
states.pop();
return argList;
}
@Override
public Instruction visitSuperNode(SuperNode iVisited) { // done
Node argsNode = iVisited.getArgsNode();
CallArgumentsList callArguments = processCallArguments(argsNode);
Node iterNode = iVisited.getIterNode();
ASTNode block = collectSingleNodeSafe(iterNode);
ISourcePosition pos = iVisited.getPosition();
RubySuperExpression expr = new RubySuperExpression(
pos.getStartOffset(), pos.getEndOffset(), callArguments, block);
states.peek().add(expr);
return null;
}
@Override
public Instruction visitToAryNode(ToAryNode iVisited) {
Iterator<Node> iterator = iVisited.childNodes().iterator();
while (iterator.hasNext()) {
iterator.next().accept(this);
}
return null;
}
@Override
public Instruction visitTrueNode(TrueNode iVisited) { // done
ISourcePosition position = iVisited.getPosition();
states.peek().add(
new BooleanLiteral(position.getStartOffset(), position
.getEndOffset(), true));
return null;
}
@Override
public Instruction visitUndefNode(UndefNode iVisited) { // done
ISourcePosition pos = iVisited.getPosition();
RubyUndefStatement s = new RubyUndefStatement(pos.getStartOffset(), pos
.getEndOffset());
states.peek().add(s);
return null;
}
@Override
public Instruction visitUntilNode(UntilNode iVisited) { // done
ASTNode condition = collectSingleNodeSafe(iVisited.getConditionNode());
ASTNode body = collectSingleNodeSafe(iVisited.getBodyNode());
ISourcePosition pos = iVisited.getPosition();
RubyUntilStatement st = new RubyUntilStatement(condition, body);
st.setStart(pos.getStartOffset());
st.setEnd(pos.getEndOffset());
states.peek().add(st);
return null;
}
@Override
public Instruction visitVAliasNode(VAliasNode iVisited) {
return null;
}
@Override
public Instruction visitVCallNode(VCallNode iVisited) {
String methodName = iVisited.getName();
if (states.isClassLikeState()) {
ClassLikeState classState = states.getClassLikeState();
if (methodName.equals("private")) //$NON-NLS-1$
classState.visibility = Modifiers.AccPrivate;
else if (methodName.equals("protected")) //$NON-NLS-1$
classState.visibility = Modifiers.AccProtected;
else if (methodName.equals("public")) //$NON-NLS-1$
classState.visibility = Modifiers.AccPublic;
}
ISourcePosition pos = iVisited.getPosition();
int funcNameStart = pos.getStartOffset();
// Assert.isTrue(funcNameStart + methodName.length() == funcNameEnd);
CallExpression c = new CallExpression(null, methodName,
CallArgumentsList.EMPTY);
c.setStart(funcNameStart);
c.setEnd(funcNameStart + methodName.length());
c.getCallName().setStart(funcNameStart);
c.getCallName().setEnd(funcNameStart + methodName.length());
this.states.peek().add(c);
return null;
}
@Override
public Instruction visitWhenNode(WhenNode iVisited) { // done
ISourcePosition position = iVisited.getPosition();
RubyWhenStatement statement = new RubyWhenStatement(position
.getStartOffset(), position.getEndOffset());
ASTNode bodyStatement = collectSingleNodeSafe(iVisited.getBodyNode());
ASTNode expressionsStatement = collectSingleNodeSafe(iVisited
.getExpressionNodes());
statement.setBody(bodyStatement);
if (expressionsStatement instanceof org.eclipse.dltk.ast.ASTListNode) {
org.eclipse.dltk.ast.ASTListNode list = (org.eclipse.dltk.ast.ASTListNode) expressionsStatement;
statement.setExpressions(list.getChilds());
} else {
List<ASTNode> list = new ArrayList<ASTNode>(1);
list.add(expressionsStatement);
statement.setExpressions(list);
}
states.peek().add(statement);
return null;
}
@Override
public Instruction visitWhileNode(WhileNode iVisited) { // done
ASTNode condition = collectSingleNodeSafe(iVisited.getConditionNode());
ASTNode body = collectSingleNodeSafe(iVisited.getBodyNode());
ISourcePosition pos = iVisited.getPosition();
RubyWhileStatement st = new RubyWhileStatement(condition, body);
st.setStart(pos.getStartOffset());
st.setEnd(pos.getEndOffset());
states.peek().add(st);
return null;
}
@Override
public Instruction visitXStrNode(XStrNode iVisited) { // done
ISourcePosition pos = iVisited.getPosition();
String value = iVisited.getValue().toString();
RubyBacktickStringLiteral s = new RubyBacktickStringLiteral(pos
.getStartOffset(), pos.getEndOffset(), value);
states.peek().add(s);
return null;
}
@Override
public Instruction visitYieldNode(YieldNode iVisited) {
ISourcePosition position = iVisited.getPosition();
RubyCallArgumentsList args = new RubyCallArgumentsList();
Node valueNode = iVisited.getArgsNode();
if (valueNode != null) {
ASTNode s = collectSingleNodeSafe(valueNode);
args.addArgument(s, 0);
}
states.peek().add(
new RubyYieldExpression(position.getStartOffset(), position
.getEndOffset(), args));
return null;
}
@Override
public Instruction visitZArrayNode(ZArrayNode iVisited) { // done
ISourcePosition pos = iVisited.getPosition();
RubyArrayExpression arr = new RubyArrayExpression();
arr.setStart(pos.getStartOffset());
arr.setEnd(pos.getEndOffset());
states.peek().add(arr);
return null;
}
@Override
public Instruction visitZSuperNode(ZSuperNode iVisited) { // done
CallArgumentsList callArguments = new CallArgumentsList(); // no
// arguments
Node iterNode = iVisited.getIterNode();
ASTNode block = collectSingleNodeSafe(iterNode);
ISourcePosition pos = iVisited.getPosition();
RubySuperExpression expr = new RubySuperExpression(
pos.getStartOffset(), pos.getEndOffset(), callArguments, block);
states.peek().add(expr);
return null;
}
/**
* @see NodeVisitor#visitBignumNode(BignumNode)
*/
@Override
public Instruction visitBignumNode(BignumNode iVisited) {// done
ISourcePosition pos = iVisited.getPosition();
BigInteger value = iVisited.getValue();
BigNumericLiteral literal = new BigNumericLiteral(pos.getStartOffset(),
pos.getEndOffset(), value);
states.peek().add(literal);
return null;
}
/**
* @see NodeVisitor#visitFixnumNode(FixnumNode)
*/
@Override
public Instruction visitFixnumNode(FixnumNode iVisited) {
ISourcePosition pos = iVisited.getPosition();
NumericLiteral node = new NumericLiteral(pos.getStartOffset(), pos
.getEndOffset(), iVisited.getValue());
states.peek().add(node);
return null;
}
/**
* @see NodeVisitor#visitFloatNode(FloatNode)
*/
@Override
public Instruction visitFloatNode(FloatNode iVisited) { // done
ISourcePosition pos = iVisited.getPosition();
double value = iVisited.getValue();
FloatNumericLiteral num = new FloatNumericLiteral(pos.getStartOffset(),
pos.getEndOffset(), value);
states.peek().add(num);
return null;
}
/**
* @see NodeVisitor#visitRegexpNode(RegexpNode)
*/
@Override
public Instruction visitRegexpNode(RegexpNode iVisited) { // done
Pattern pattern = iVisited.getPattern();
ISourcePosition position = iVisited.getPosition();
String value = iVisited.getValue().toString();
RubyRegexpExpression e = new RubyRegexpExpression(position
.getStartOffset(), position.getEndOffset(), value);
e.setPattern(pattern);
states.peek().add(e);
return null;
}
/**
* @see NodeVisitor#visitSymbolNode(SymbolNode)
*/
@Override
public Instruction visitSymbolNode(SymbolNode iVisited) { // done
final String symName = iVisited.getName();
final ISourcePosition position = iVisited.getPosition();
final int start = position.getStartOffset();
int nameLen = symName.length();
if (content[start] == ':') {
++nameLen;
}
int end = position.getEndOffset();
if (end - start > nameLen) {
end = start + nameLen;
}
RubySymbolReference sr = new RubySymbolReference(start, end, symName);
states.peek().add(sr);
return null;
}
@Override
public Instruction visitArgsPushNode(ArgsPushNode arg0) {
// TODO Auto-generated method stub
return null;
}
@Override
public Instruction visitAttrAssignNode(AttrAssignNode arg0) { // done
ASTNode receiver = collectSingleNodeSafe(arg0.getReceiverNode());
CallArgumentsList list = processCallArguments(arg0.getArgsNode());
CallExpression expr = new CallExpression(receiver, arg0.getName(), list);
copyOffsets(expr, arg0);
int possNameStart = arg0.getPosition().getStartOffset();
if (receiver != null)
possNameStart = receiver.sourceEnd() + 1;
fixFunctionCallOffsets(expr, arg0.getName(), possNameStart, list
.sourceStart(), list.sourceEnd());
states.peek().add(expr);
return null;
}
@Override
public Instruction visitRootNode(RootNode arg0) { // done
Node bodyNode = arg0.getBodyNode();
if (bodyNode instanceof BlockNode) {
BlockNode blockNode = (BlockNode) bodyNode;
Iterator<Node> iterator = blockNode.childNodes().iterator();
while (iterator.hasNext()) {
iterator.next().accept(this);
}
} else if (bodyNode != null)
bodyNode.accept(this);
return null;
}
}