package dk.brics.jspointers.flowgraph.analysis;
import dk.brics.tajs.flowgraph.Node;
import dk.brics.tajs.flowgraph.NodeVisitor;
import dk.brics.tajs.flowgraph.nodes.AssumeNode;
import dk.brics.tajs.flowgraph.nodes.BinaryOperatorNode;
import dk.brics.tajs.flowgraph.nodes.CallNode;
import dk.brics.tajs.flowgraph.nodes.CatchNode;
import dk.brics.tajs.flowgraph.nodes.ConstantNode;
import dk.brics.tajs.flowgraph.nodes.DeclareEventHandlerNode;
import dk.brics.tajs.flowgraph.nodes.DeclareFunctionNode;
import dk.brics.tajs.flowgraph.nodes.DeclareVariableNode;
import dk.brics.tajs.flowgraph.nodes.DeletePropertyNode;
import dk.brics.tajs.flowgraph.nodes.EnterWithNode;
import dk.brics.tajs.flowgraph.nodes.EventDispatcherNode;
import dk.brics.tajs.flowgraph.nodes.EventEntryNode;
import dk.brics.tajs.flowgraph.nodes.ExceptionalReturnNode;
import dk.brics.tajs.flowgraph.nodes.GetPropertiesNode;
import dk.brics.tajs.flowgraph.nodes.HasNextPropertyNode;
import dk.brics.tajs.flowgraph.nodes.IfNode;
import dk.brics.tajs.flowgraph.nodes.LeaveWithNode;
import dk.brics.tajs.flowgraph.nodes.NewObjectNode;
import dk.brics.tajs.flowgraph.nodes.NextPropertyNode;
import dk.brics.tajs.flowgraph.nodes.NopNode;
import dk.brics.tajs.flowgraph.nodes.ReadPropertyNode;
import dk.brics.tajs.flowgraph.nodes.ReadVariableNode;
import dk.brics.tajs.flowgraph.nodes.ReturnNode;
import dk.brics.tajs.flowgraph.nodes.ThrowNode;
import dk.brics.tajs.flowgraph.nodes.TypeofNode;
import dk.brics.tajs.flowgraph.nodes.UnaryOperatorNode;
import dk.brics.tajs.flowgraph.nodes.WritePropertyNode;
import dk.brics.tajs.flowgraph.nodes.WriteVariableNode;
/**
* Determines which relevant variables are read for each node. This may differ
* from what variables the node would actually use if evaluated runtime, due
* to the abstractions made by the analysis.
* <p/>
* For example, in the statement <tt>x = y * z</tt>, the variables <tt>y,z</tt> will
* not be considered relevant, because the analysis knows the result is a number regardless
* of their value.
*/
public class ReadVarsVisitor implements NodeVisitor<Void>, ReadVarsInterface {
private int[] result;
private static int[] NONE = new int[0];
public int[] getReadVars(Node node) {
result=null;
node.visitBy(this, null);
if (result == null)
throw new RuntimeException("Error in ReadVarsVisitor for node " + node.getClass());
return result;
}
public void visit(AssumeNode n, Void a) {
result = NONE;
}
public void visit(BinaryOperatorNode n, Void a) {
if (n.getOperator() == BinaryOperatorNode.Op.ADD) {
// only + is where we care about the arguments, to distinguish numbers and strings
result = new int[] {n.getArg1Var(), n.getArg2Var()};
} else {
result = NONE; // the operands are irrelevant for the type-system
}
}
public void visit(CallNode n, Void a) {
if (n.getBaseVar() != Node.NO_VALUE) {
result = new int[n.getNumberOfArgs() + 2];
result[0] = n.getBaseVar();
result[1] = n.getFunctionVar();
for (int i=0; i<n.getNumberOfArgs(); i++) {
result[i+2] = n.getArgVar(i);
}
} else {
result = new int[n.getNumberOfArgs() + 1];
result[0] = n.getFunctionVar();
for (int i=0; i<n.getNumberOfArgs(); i++) {
result[i+1] = n.getArgVar(i);
}
}
}
public void visit(CatchNode n, Void a) {
result = NONE;
}
public void visit(ConstantNode n, Void a) {
result = NONE;
}
public void visit(DeletePropertyNode n, Void a) {
result = NONE; // because we don't model it (FIXME)
}
public void visit(EnterWithNode n, Void a) {
result = new int[] {n.getObjectVar()};
}
public void visit(ExceptionalReturnNode n, Void a) {
result = NONE;
}
public void visit(DeclareFunctionNode n, Void a) {
result = NONE;
}
public void visit(GetPropertiesNode n, Void a) {
result = NONE; // because we don't model it (FIXME)
}
public void visit(IfNode n, Void a) {
result = NONE;
}
public void visit(LeaveWithNode n, Void a) {
result = NONE;
}
public void visit(NewObjectNode n, Void a) {
result = NONE;
}
public void visit(NextPropertyNode n, Void a) {
result = NONE;
}
public void visit(HasNextPropertyNode n, Void a) {
result = NONE;
}
public void visit(NopNode n, Void a) {
result = NONE;
}
public void visit(ReadPropertyNode n, Void a) {
if (n.getPropertyStr() != null) {
result = new int[] {n.getBaseVar()};
} else {
result = new int[] {n.getBaseVar(), n.getPropertyVar()};
}
}
public void visit(ReadVariableNode n, Void a) {
result = NONE;
}
public void visit(ReturnNode n, Void a) {
if (n.getValueVar() != Node.NO_VALUE) {
result = new int[] {n.getValueVar()};
} else {
result = NONE;
}
}
public void visit(ThrowNode n, Void a) {
result = new int[] {n.getValueVar()};
}
public void visit(TypeofNode n, Void a) {
if (n.getArgVar() != Node.NO_VALUE) {
result = new int[] {n.getArgVar()};
} else {
result = NONE;
}
}
public void visit(UnaryOperatorNode n, Void a) {
result = NONE; // the operand is irrelevant for the type-system
}
public void visit(DeclareVariableNode n, Void a) {
result = NONE;
}
public void visit(WritePropertyNode n, Void a) {
if (n.getPropertyStr() != null) {
result = new int[] {n.getBaseVar(), n.getValueVar()};
} else {
result = new int[] {n.getBaseVar(), n.getPropertyVar(), n.getValueVar()};
}
}
public void visit(WriteVariableNode n, Void a) {
result = new int[] {n.getValueVar()};
}
public void visit(EventDispatcherNode n, Void a) {
result = NONE;
}
public void visit(DeclareEventHandlerNode n, Void a) {
result = NONE;
}
public void visit(EventEntryNode n, Void a) {
result = NONE;
}
}