2007-04-19 13:53:31 +00:00
|
|
|
package com.ibm.wala.cast.js.translator;
|
|
|
|
|
|
|
|
import java.util.Map;
|
|
|
|
|
2007-07-13 22:46:19 +00:00
|
|
|
import com.ibm.wala.cast.ir.translator.AstTranslator.InternalCAstSymbol;
|
2007-07-06 22:09:08 +00:00
|
|
|
import com.ibm.wala.cast.tree.CAst;
|
|
|
|
import com.ibm.wala.cast.tree.CAstNode;
|
|
|
|
import com.ibm.wala.cast.tree.impl.CAstOperator;
|
|
|
|
import com.ibm.wala.cast.tree.impl.CAstRewriter;
|
|
|
|
import com.ibm.wala.util.debug.Assertions;
|
|
|
|
|
2007-04-19 13:53:31 +00:00
|
|
|
public class PropertyReadExpander extends CAstRewriter<PropertyReadExpander.RewriteContext> {
|
|
|
|
|
|
|
|
private int readTempCounter = 0;
|
|
|
|
|
|
|
|
private static final String TEMP_NAME = "readTemp";
|
|
|
|
|
|
|
|
interface RewriteContext {
|
|
|
|
|
|
|
|
boolean inRead();
|
|
|
|
|
|
|
|
boolean inAssignment();
|
|
|
|
|
|
|
|
void setAssign(CAstNode receiverTemp, CAstNode elementTemp);
|
|
|
|
}
|
|
|
|
|
|
|
|
private final class AssignOpContext implements RewriteContext {
|
|
|
|
private CAstNode receiverTemp;
|
|
|
|
private CAstNode elementTemp;
|
|
|
|
|
|
|
|
public boolean inAssignment() {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean inRead() {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setAssign(CAstNode receiverTemp, CAstNode elementTemp) {
|
|
|
|
this.receiverTemp = receiverTemp;
|
|
|
|
this.elementTemp = elementTemp;
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
private static final RewriteContext READ = new RewriteContext() {
|
|
|
|
public boolean inAssignment() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean inRead() {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setAssign(CAstNode receiverTemp, CAstNode elementTemp) {
|
|
|
|
Assertions.UNREACHABLE();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
private static final RewriteContext ASSIGN = new RewriteContext() {
|
|
|
|
public boolean inAssignment() {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean inRead() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setAssign(CAstNode receiverTemp, CAstNode elementTemp) {
|
|
|
|
Assertions.UNREACHABLE();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
public PropertyReadExpander(CAst Ast) {
|
|
|
|
super(Ast, true, READ);
|
|
|
|
}
|
|
|
|
|
|
|
|
private CAstNode makeConstRead(CAstNode receiver,
|
|
|
|
CAstNode element,
|
|
|
|
RewriteContext context)
|
|
|
|
{
|
|
|
|
String receiverTemp = TEMP_NAME + (readTempCounter++);
|
|
|
|
String elt = (String) element.getValue();
|
|
|
|
|
|
|
|
if (context.inAssignment()) {
|
|
|
|
context.setAssign(
|
|
|
|
Ast.makeNode(CAstNode.VAR, Ast.makeConstant(receiverTemp)),
|
|
|
|
Ast.makeConstant(elt));
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
Ast.makeNode(CAstNode.BLOCK_EXPR,
|
|
|
|
Ast.makeNode(CAstNode.DECL_STMT,
|
2007-07-13 22:46:19 +00:00
|
|
|
Ast.makeConstant(new InternalCAstSymbol(receiverTemp, false, false)),
|
2007-04-19 13:53:31 +00:00
|
|
|
receiver),
|
|
|
|
Ast.makeNode(CAstNode.LOOP,
|
|
|
|
Ast.makeNode(CAstNode.UNARY_EXPR,
|
|
|
|
CAstOperator.OP_NOT,
|
|
|
|
Ast.makeNode(CAstNode.IS_DEFINED_EXPR,
|
|
|
|
Ast.makeNode(CAstNode.VAR, Ast.makeConstant(receiverTemp)),
|
|
|
|
Ast.makeConstant(elt))),
|
|
|
|
Ast.makeNode(CAstNode.ASSIGN,
|
|
|
|
Ast.makeNode(CAstNode.VAR, Ast.makeConstant(receiverTemp)),
|
|
|
|
Ast.makeNode(CAstNode.OBJECT_REF,
|
|
|
|
Ast.makeNode(CAstNode.VAR, Ast.makeConstant(receiverTemp)),
|
|
|
|
Ast.makeConstant("prototype")))),
|
|
|
|
Ast.makeNode(CAstNode.OBJECT_REF,
|
|
|
|
Ast.makeNode(CAstNode.VAR, Ast.makeConstant(receiverTemp)),
|
|
|
|
Ast.makeConstant(elt)));
|
|
|
|
}
|
|
|
|
|
|
|
|
private CAstNode makeVarRead(CAstNode receiver,
|
|
|
|
CAstNode element,
|
|
|
|
RewriteContext context)
|
|
|
|
{
|
|
|
|
String receiverTemp = TEMP_NAME + (readTempCounter++);
|
|
|
|
String elementTemp = TEMP_NAME + (readTempCounter++);
|
|
|
|
|
|
|
|
if (context.inAssignment()) {
|
|
|
|
context.setAssign(
|
|
|
|
Ast.makeNode(CAstNode.VAR, Ast.makeConstant(receiverTemp)),
|
|
|
|
Ast.makeNode(CAstNode.VAR, Ast.makeConstant(elementTemp)));
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
Ast.makeNode(CAstNode.BLOCK_EXPR,
|
|
|
|
Ast.makeNode(CAstNode.DECL_STMT,
|
2007-07-13 22:46:19 +00:00
|
|
|
Ast.makeConstant(new InternalCAstSymbol(receiverTemp, false, false)),
|
2007-04-19 13:53:31 +00:00
|
|
|
receiver),
|
|
|
|
Ast.makeNode(CAstNode.DECL_STMT,
|
2007-07-13 22:46:19 +00:00
|
|
|
Ast.makeConstant(new InternalCAstSymbol(elementTemp, false, false)),
|
2007-04-19 13:53:31 +00:00
|
|
|
element),
|
|
|
|
Ast.makeNode(CAstNode.LOOP,
|
|
|
|
Ast.makeNode(CAstNode.UNARY_EXPR,
|
|
|
|
CAstOperator.OP_NOT,
|
|
|
|
Ast.makeNode(CAstNode.IS_DEFINED_EXPR,
|
|
|
|
Ast.makeNode(CAstNode.VAR, Ast.makeConstant(receiverTemp)),
|
|
|
|
Ast.makeNode(CAstNode.VAR, Ast.makeConstant(elementTemp)))),
|
|
|
|
Ast.makeNode(CAstNode.ASSIGN,
|
|
|
|
Ast.makeNode(CAstNode.VAR, Ast.makeConstant(receiverTemp)),
|
|
|
|
Ast.makeNode(CAstNode.OBJECT_REF,
|
|
|
|
Ast.makeNode(CAstNode.VAR, Ast.makeConstant(receiverTemp)),
|
|
|
|
Ast.makeConstant("prototype")))),
|
|
|
|
Ast.makeNode(CAstNode.OBJECT_REF,
|
|
|
|
Ast.makeNode(CAstNode.VAR, Ast.makeConstant(receiverTemp)),
|
|
|
|
Ast.makeNode(CAstNode.VAR, Ast.makeConstant(elementTemp))));
|
|
|
|
}
|
|
|
|
|
|
|
|
protected CAstNode copyNodes(CAstNode root,
|
|
|
|
RewriteContext context,
|
|
|
|
Map<CAstNode, CAstNode> nodeMap)
|
|
|
|
{
|
|
|
|
int kind = root.getKind();
|
|
|
|
|
|
|
|
if (kind == CAstNode.OBJECT_REF && context.inRead()) {
|
|
|
|
CAstNode readLoop;
|
|
|
|
CAstNode receiver = copyNodes(root.getChild(0), READ, nodeMap);
|
|
|
|
CAstNode element = copyNodes(root.getChild(1), READ, nodeMap);
|
|
|
|
if (element.getKind()==CAstNode.CONSTANT && element.getValue() instanceof String) {
|
|
|
|
readLoop= makeConstRead(receiver, element, context);
|
|
|
|
} else {
|
|
|
|
readLoop= makeVarRead(receiver, element, context);
|
|
|
|
}
|
|
|
|
nodeMap.put(root, readLoop);
|
|
|
|
return readLoop;
|
|
|
|
|
|
|
|
} else if (kind==CAstNode.ASSIGN_PRE_OP || kind==CAstNode.ASSIGN_POST_OP) {
|
|
|
|
AssignOpContext ctxt = new AssignOpContext();
|
|
|
|
CAstNode lval = copyNodes(root.getChild(0), ctxt, nodeMap);
|
|
|
|
CAstNode rval = copyNodes(root.getChild(1), READ, nodeMap);
|
|
|
|
CAstNode op = copyNodes(root.getChild(2), READ, nodeMap);
|
|
|
|
if (ctxt.receiverTemp != null) {
|
|
|
|
String temp1 = TEMP_NAME + (readTempCounter++);
|
|
|
|
String temp2 = TEMP_NAME + (readTempCounter++);
|
|
|
|
CAstNode copy = Ast.makeNode(CAstNode.BLOCK_EXPR,
|
|
|
|
Ast.makeNode(CAstNode.DECL_STMT,
|
2007-07-13 22:46:19 +00:00
|
|
|
Ast.makeConstant(new InternalCAstSymbol(temp1, true, false)),
|
2007-04-19 13:53:31 +00:00
|
|
|
lval),
|
|
|
|
rval,
|
|
|
|
Ast.makeNode(CAstNode.DECL_STMT,
|
2007-07-13 22:46:19 +00:00
|
|
|
Ast.makeConstant(new InternalCAstSymbol(temp2, true, false)),
|
2007-04-19 13:53:31 +00:00
|
|
|
Ast.makeNode(CAstNode.BINARY_EXPR, op,
|
|
|
|
Ast.makeNode(CAstNode.VAR, Ast.makeConstant(temp1)),
|
|
|
|
rval)),
|
|
|
|
Ast.makeNode(CAstNode.ASSIGN,
|
|
|
|
Ast.makeNode(CAstNode.OBJECT_REF,
|
|
|
|
ctxt.receiverTemp,
|
|
|
|
ctxt.elementTemp),
|
|
|
|
Ast.makeNode(CAstNode.VAR, Ast.makeConstant(temp2))),
|
|
|
|
Ast.makeNode(CAstNode.VAR,
|
|
|
|
Ast.makeConstant((kind==CAstNode.ASSIGN_PRE_OP)? temp2: temp1)));
|
|
|
|
nodeMap.put(root,copy);
|
|
|
|
return copy;
|
|
|
|
} else {
|
|
|
|
CAstNode copy = Ast.makeNode(kind, lval, rval, op);
|
|
|
|
nodeMap.put(root,copy);
|
|
|
|
return copy;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else if (kind == CAstNode.ASSIGN) {
|
|
|
|
CAstNode copy = Ast.makeNode(CAstNode.ASSIGN,
|
|
|
|
copyNodes(root.getChild(0), ASSIGN, nodeMap),
|
|
|
|
copyNodes(root.getChild(1), READ, nodeMap));
|
|
|
|
nodeMap.put(root,copy);
|
|
|
|
return copy;
|
|
|
|
|
|
|
|
} else if (kind == CAstNode.BLOCK_EXPR) {
|
|
|
|
CAstNode children[] = new CAstNode[ root.getChildCount() ];
|
|
|
|
int last = (children.length - 1);
|
|
|
|
for(int i = 0; i < last; i++) {
|
|
|
|
children[i] = copyNodes(root.getChild(i), READ, nodeMap);
|
|
|
|
}
|
|
|
|
children[last] = copyNodes(root.getChild(last), context, nodeMap);
|
|
|
|
|
|
|
|
CAstNode copy = Ast.makeNode(CAstNode.BLOCK_EXPR, children);
|
|
|
|
nodeMap.put(root,copy);
|
|
|
|
return copy;
|
|
|
|
|
|
|
|
} else if (root.getKind() == CAstNode.CONSTANT) {
|
|
|
|
CAstNode copy = Ast.makeConstant( root.getValue() );
|
|
|
|
nodeMap.put(root,copy);
|
|
|
|
return copy;
|
|
|
|
|
|
|
|
} else if (root.getKind() == CAstNode.OPERATOR) {
|
|
|
|
nodeMap.put(root,root);
|
|
|
|
return root;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
CAstNode children[] = new CAstNode[ root.getChildCount() ];
|
|
|
|
for(int i = 0; i < children.length; i++) {
|
|
|
|
children[i] = copyNodes(root.getChild(i), READ, nodeMap);
|
|
|
|
}
|
|
|
|
CAstNode copy = Ast.makeNode(kind, children);
|
|
|
|
nodeMap.put(root,copy);
|
|
|
|
return copy;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|