/*
* Created on Sep 8, 2005
*/
package x10.wala.translator;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import polyglot.ast.ArrayAccess;
import polyglot.ast.ArrayAccessAssign;
import polyglot.ast.ArrayInit;
import polyglot.ast.ArrayTypeNode;
import polyglot.ast.Assert;
import polyglot.ast.Assign;
import polyglot.ast.Binary;
import polyglot.ast.Block;
import polyglot.ast.BooleanLit;
import polyglot.ast.Branch;
import polyglot.ast.Call;
import polyglot.ast.CanonicalTypeNode;
import polyglot.ast.Case;
import polyglot.ast.Cast;
import polyglot.ast.Catch;
import polyglot.ast.CharLit;
import polyglot.ast.ClassBody;
import polyglot.ast.ClassDecl;
import polyglot.ast.ClassLit;
import polyglot.ast.ClassMember;
import polyglot.ast.Conditional;
import polyglot.ast.ConstructorCall;
import polyglot.ast.ConstructorDecl;
import polyglot.ast.Do;
import polyglot.ast.Empty;
import polyglot.ast.Eval;
import polyglot.ast.Expr;
import polyglot.ast.Field;
import polyglot.ast.FieldAssign;
import polyglot.ast.FieldDecl;
import polyglot.ast.FloatLit;
import polyglot.ast.For;
import polyglot.ast.Formal;
import polyglot.ast.Id;
import polyglot.ast.If;
import polyglot.ast.Import;
import polyglot.ast.Initializer;
import polyglot.ast.Instanceof;
import polyglot.ast.IntLit;
import polyglot.ast.Labeled;
import polyglot.ast.Local;
import polyglot.ast.LocalAssign;
import polyglot.ast.LocalClassDecl;
import polyglot.ast.LocalDecl;
import polyglot.ast.MethodDecl;
import polyglot.ast.New;
import polyglot.ast.NewArray;
import polyglot.ast.Node;
import polyglot.ast.NodeFactory;
import polyglot.ast.NullLit;
import polyglot.ast.PackageNode;
import polyglot.ast.ProcedureDecl;
import polyglot.ast.Receiver;
import polyglot.ast.Return;
import polyglot.ast.SourceFile;
import polyglot.ast.Special;
import polyglot.ast.Stmt;
import polyglot.ast.StringLit;
import polyglot.ast.Switch;
import polyglot.ast.SwitchBlock;
import polyglot.ast.SwitchElement;
import polyglot.ast.Throw;
import polyglot.ast.TopLevelDecl;
import polyglot.ast.Try;
import polyglot.ast.Unary;
import polyglot.ast.While;
import polyglot.ast.Binary.Operator;
import polyglot.ast.ConstructorCall.Kind;
import polyglot.types.ClassType;
import polyglot.types.CodeInstance;
import polyglot.types.ConstructorInstance;
import polyglot.types.ContainerType;
import polyglot.types.Context;
import polyglot.types.FieldInstance;
import polyglot.types.Flags;
import polyglot.types.InitializerDef;
import polyglot.types.InitializerInstance;
import polyglot.types.LocalDef;
import polyglot.types.MemberDef;
import polyglot.types.JavaArrayType;
import polyglot.types.Name;
import polyglot.types.ObjectType;
import polyglot.types.ProcedureInstance;
import polyglot.types.QName;
import polyglot.types.SemanticException;
import polyglot.types.Type;
import polyglot.types.TypeSystem;
import polyglot.types.Types;
import x10.ast.AssignPropertyCall;
import x10.ast.Async;
import x10.ast.AtEach;
import x10.ast.AtStmt;
import x10.ast.Atomic;
import x10.ast.Clocked;
import x10.ast.Closure;
import x10.ast.ClosureCall;
import x10.ast.Finish;
import x10.ast.ForLoop;
import x10.ast.Here;
import x10.ast.LocalTypeDef;
import x10.ast.Next;
import x10.ast.ParExpr;
import x10.ast.SettableAssign;
import x10.ast.StmtSeq;
import x10.ast.Tuple;
import x10.ast.TypeDecl;
import x10.ast.When;
import x10.ast.When_c;
import x10.ast.X10Formal;
import x10.ast.X10Loop;
import x10.types.FunctionType;
import x10.types.MethodInstance;
import x10.types.MethodInstance_c;
import x10.types.ParametrizedType;
import x10.wala.tree.X10CAstEntity;
import x10.wala.tree.X10CastNode;
import polyglot.types.TypeSystem;
import polyglot.util.Position;
import com.ibm.wala.cast.ir.translator.AstTranslator.InternalCAstSymbol;
import com.ibm.wala.cast.java.loader.Util;
import com.ibm.wala.cast.java.translator.JavaProcedureEntity;
import com.ibm.wala.cast.java.translator.TranslatorToCAst;
import com.ibm.wala.cast.java.types.JavaType;
import com.ibm.wala.cast.tree.CAst;
import com.ibm.wala.cast.tree.CAstControlFlowMap;
import com.ibm.wala.cast.tree.CAstEntity;
import com.ibm.wala.cast.tree.CAstNode;
import com.ibm.wala.cast.tree.CAstNodeTypeMap;
import com.ibm.wala.cast.tree.CAstQualifier;
import com.ibm.wala.cast.tree.CAstSourcePositionMap;
import com.ibm.wala.cast.tree.CAstSymbol;
import com.ibm.wala.cast.tree.CAstType;
import com.ibm.wala.cast.tree.CAstTypeDictionary;
import com.ibm.wala.cast.tree.impl.AbstractSourcePosition;
import com.ibm.wala.cast.tree.impl.CAstCloner;
import com.ibm.wala.cast.tree.impl.CAstControlFlowRecorder;
import com.ibm.wala.cast.tree.impl.CAstImpl;
import com.ibm.wala.cast.tree.impl.CAstNodeTypeMapRecorder;
import com.ibm.wala.cast.tree.impl.CAstOperator;
import com.ibm.wala.cast.tree.impl.CAstRewriter;
import com.ibm.wala.cast.tree.impl.CAstSourcePositionRecorder;
import com.ibm.wala.cast.tree.impl.CAstSymbolImpl;
import com.ibm.wala.classLoader.CallSiteReference;
import com.ibm.wala.shrikeBT.IInvokeInstruction;
import com.ibm.wala.types.ClassLoaderReference;
import com.ibm.wala.types.Descriptor;
import com.ibm.wala.types.FieldReference;
import com.ibm.wala.types.MethodReference;
import com.ibm.wala.types.Selector;
import com.ibm.wala.types.TypeName;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.collections.EmptyIterator;
import com.ibm.wala.util.collections.HashMapFactory;
import com.ibm.wala.util.collections.IteratorPlusOne;
import com.ibm.wala.util.collections.Pair;
import com.ibm.wala.util.debug.Assertions;
import com.ibm.wala.util.strings.Atom;
public class X10toCAstTranslator implements TranslatorToCAst {
protected final CAst fFactory = new CAstImpl();
protected final NodeFactory fNodeFactory;
protected final TypeSystem fTypeSystem;
protected Type fNPEType;
protected Type fCCEType;
protected Type fEType; // Exception
protected Type fDivByZeroType;
protected final ClassLoaderReference fClassLoaderRef;
private CAstTypeDictionary fTypeDict;
private X10TranslatorVisitor fTranslator;
protected X10IdentityMapper fIdentityMapper;
protected boolean replicateForDoLoops = false;
protected final boolean DEBUG = true;
final protected X10TranslatorVisitor getTranslator() {
if (fTranslator == null)
fTranslator = createTranslator();
return fTranslator;
}
protected CAstTypeDictionary getTypeDict() {
if (fTypeDict == null) {
fTypeDict = createTypeDict();
}
return fTypeDict;
}
protected X10TypeDictionary createTypeDict() {
return new X10TypeDictionary(fTypeSystem, this);
}
protected static CAstOperator mapUnaryOpcode(Unary.Operator operator) {
if (operator.equals(Unary.BIT_NOT))
return CAstOperator.OP_BITNOT;
if (operator.equals(Unary.NEG))
return CAstOperator.OP_SUB; // CAst will handle OP_SUB with only 1
// arg properly !!! Hah!
if (operator.equals(Unary.NOT))
return CAstOperator.OP_NOT;
if (operator.equals(Unary.POS))
return CAstOperator.OP_ADD; // CAst will throw away OP_ADD with only
// 1 arg!!!
if (operator.equals(Unary.POST_DEC))
return CAstOperator.OP_SUB; // translator will produce different
// CAstNode types for post dec
if (operator.equals(Unary.POST_INC))
return CAstOperator.OP_ADD; // translator will produce different
// CAstNode types for post inc
if (operator.equals(Unary.PRE_DEC))
return CAstOperator.OP_SUB; // translator will produce different
// CAstNode types for pre dec
if (operator.equals(Unary.PRE_INC))
return CAstOperator.OP_ADD; // translator will produce different
// CAstNode types for pre inc
Assertions.UNREACHABLE("Java2CAstTranslator.JavaTranslatingVisitorImpl.mapUnaryOpcode(): unrecognized unary operator.");
return null;
}
protected static CAstOperator mapBinaryOpcode(Binary.Operator operator) {
if (operator.equals(Binary.ADD))
return CAstOperator.OP_ADD;
if (operator.equals(Binary.BIT_AND))
return CAstOperator.OP_BIT_AND;
if (operator.equals(Binary.BIT_OR))
return CAstOperator.OP_BIT_OR;
if (operator.equals(Binary.BIT_XOR))
return CAstOperator.OP_BIT_XOR;
if (operator.equals(Binary.COND_AND))
return CAstOperator.OP_REL_AND;
if (operator.equals(Binary.COND_OR))
return CAstOperator.OP_REL_OR;
if (operator.equals(Binary.DIV))
return CAstOperator.OP_DIV;
if (operator.equals(Binary.EQ))
return CAstOperator.OP_EQ;
if (operator.equals(Binary.GE))
return CAstOperator.OP_GE;
if (operator.equals(Binary.GT))
return CAstOperator.OP_GT;
if (operator.equals(Binary.LE))
return CAstOperator.OP_LE;
if (operator.equals(Binary.LT))
return CAstOperator.OP_LT;
if (operator.equals(Binary.MOD))
return CAstOperator.OP_MOD;
if (operator.equals(Binary.MUL))
return CAstOperator.OP_MUL;
if (operator.equals(Binary.NE))
return CAstOperator.OP_NE;
if (operator.equals(Binary.SHL))
return CAstOperator.OP_LSH;
if (operator.equals(Binary.SHR))
return CAstOperator.OP_RSH;
if (operator.equals(Binary.SUB))
return CAstOperator.OP_SUB;
if (operator.equals(Binary.USHR))
return CAstOperator.OP_URSH;
Assertions.UNREACHABLE("Java2CAstTranslator.JavaTranslatingVisitorImpl.mapBinaryOpcode(): unrecognized binary operator.");
return null;
}
protected CAstNode translateConstant(x10.types.constants.ConstantValue constant) {
return fFactory.makeConstant(constant.toJavaObject());
}
protected class JavaTranslatingVisitorImpl {
public CAstNode visit(MethodDecl m, WalkContext mc) {
if (m.body() == null || m.body().statements().size() == 0)
return makeNode(mc, fFactory, m, CAstNode.RETURN);
else
return walkNodes(m.body(), mc);
}
public CAstNode visit(ConstructorDecl cd, WalkContext mc) {
// Needs to examine the initializers in the ClassContext
// and glue that code into the right place relative to the
// constructor method body ("wherever that may turn out to be").
List/* <FieldDecl|Initializer> */inits = mc.getInitializers();
Block body = cd.body();
if (hasSuperCall(body)) {
// Split at call to super:
// super();
// field initializer code
// remainder of ctor body
CAstNode[] bodyNodes = new CAstNode[inits.size() + body.statements().size()];
int idx = 0;
for (Iterator iter = body.statements().iterator(); iter.hasNext();) {
Stmt s = (Stmt) iter.next();
bodyNodes[idx++] = walkNodes(s, mc);
if (idx == 1) {
Assertions.productionAssertion(isSpecialCallStmt(s, ConstructorCall.SUPER));
idx = insertInitializers(mc, bodyNodes, false, idx);
}
}
return makeNode(mc, fFactory, body, CAstNode.BLOCK_STMT, bodyNodes);
} else if (hasThisCall(body)) {
return walkNodes(body, mc);
} else {
// add explicit call to default super()
// RMF 4/17/2009- The following search for a superClass default ctor
// won't work if we process Object in source. In particular, the
// superClass might be null. In that case, simply omit the explicit
// super() call.
ClassType superClass = (ClassType) ((ObjectType) cd.constructorDef().asInstance().container()).superClass();
CAstNode[] bodyNodes;
int idx= 0;
int bodyInitsSize= inits.size() + body.statements().size();
if (superClass != null) {
ProcedureInstance defaultSuperCtor = findDefaultCtor(superClass);
CallSiteReference callSiteRef = CallSiteReference.make(0, fIdentityMapper.getMethodRef(defaultSuperCtor),
IInvokeInstruction.Dispatch.SPECIAL);
CAstNode superCall = makeNode(mc, fFactory, cd, CAstNode.CALL,
makeNode(mc, fFactory, cd, CAstNode.SUPER),
fFactory.makeConstant(callSiteRef));
bodyNodes = new CAstNode[bodyInitsSize + 1];
bodyNodes[idx++] = superCall;
} else { // no super class, so no super call
bodyNodes = new CAstNode[bodyInitsSize];
}
idx= insertInitializers(mc, bodyNodes, false, idx);
for (Iterator iter = body.statements().iterator(); iter.hasNext(); idx++) {
Stmt s = (Stmt) iter.next();
bodyNodes[idx] = walkNodes(s, mc);
}
return makeNode(mc, fFactory, body, CAstNode.BLOCK_STMT, bodyNodes);
}
}
private ProcedureInstance findDefaultCtor(ClassType superClass) {
List/* <ProcedureInstance> */ctors = superClass.constructors();
for (Iterator iter = ctors.iterator(); iter.hasNext();) {
ConstructorInstance ctor = (ConstructorInstance) iter.next();
if (ctor.formalTypes().isEmpty())
return ctor;
}
Assertions.UNREACHABLE("Couldn't find default ctor");
return null;
}
public CAstNode visit(FieldDecl f, WalkContext ctorContext) {
// Generate CAST node for the initializer (init())
// Type targetType = f.memberInstance().container();
// Type fieldType = f.type().type();
FieldReference fieldRef = fIdentityMapper.getFieldRef(f.fieldDef().asInstance());
// We use null to indicate an OBJECT_REF to a static field, as the
// FieldReference doesn't
// hold enough info to determine this. In this case, (unlike field ref)
// we don't have a
// target expr to evaluate.
CAstNode thisNode = f.flags().flags().isStatic() ? makeNode(ctorContext, fFactory, null, CAstNode.VOID) : makeNode(ctorContext,
fFactory, f, CAstNode.THIS);
CAstNode lhsNode = makeNode(ctorContext, fFactory, f, CAstNode.OBJECT_REF, thisNode, fFactory.makeConstant(fieldRef));
Expr init = f.init();
CAstNode rhsNode;
if (init instanceof ArrayInit) {
rhsNode = visit((ArrayInit) init, ctorContext, f.declType());
} else {
rhsNode = walkNodes(init, ctorContext);
}
CAstNode assNode = makeNode(ctorContext, fFactory, f, CAstNode.ASSIGN, lhsNode, rhsNode);
return assNode;
}
public CAstNode visit(Import i, WalkContext wc) {
Assertions.UNREACHABLE("walkNodes.ASTTraverser.visit(Import)");
return null;
}
public CAstNode visit(PackageNode p, WalkContext wc) {
Assertions.UNREACHABLE("walkNodes.ASTTraverser.visit(PackageNode)");
return null;
}
public CAstNode visit(CanonicalTypeNode ctn, WalkContext wc) {
// We'll take care of this in its surrounding context...
return makeNode(wc, fFactory, null, CAstNode.EMPTY);
}
public CAstNode visit(ArrayTypeNode ctn, WalkContext wc) {
// We'll take care of this in its surrounding context...
Assertions.UNREACHABLE("walkNodes.ASTTraverser.visit(CanonicalTypeNode)");
return null;
}
/*
* If we've handled all the parent cases, this should never be called --
* visit(ArrayInit,WalkContext,Type) should be instead.
*/
public CAstNode visit(ArrayInit ai, WalkContext wc) {
if (((JavaArrayType) ai.type()).base().isNull()) {
Assertions.productionAssertion(false, "bad type " + ai.type() + " for " + ai + " at " + ai.position());
}
TypeReference newTypeRef = fIdentityMapper.getTypeRef(ai.type());
CAstNode[] eltNodes = new CAstNode[ai.elements().size() + 1];
int idx = 0;
eltNodes[idx++] = makeNode(wc, fFactory, ai, CAstNode.NEW, fFactory.makeConstant(newTypeRef), fFactory.makeConstant(ai
.elements().size()));
for (Iterator iter = ai.elements().iterator(); iter.hasNext(); idx++) {
Expr element = (Expr) iter.next();
if ( element instanceof ArrayInit ) {
eltNodes[idx] = visit((ArrayInit)element, wc, ((JavaArrayType)ai.type()).base());
} else {
eltNodes[idx] = walkNodes(element, wc);
}
if (eltNodes[idx] == null) {
Assertions.productionAssertion(eltNodes[idx] != null, element.toString());
}
}
return makeNode(wc, fFactory, ai, CAstNode.ARRAY_LITERAL, eltNodes);
}
/*
* Workaround for the null array init bug: just in case ai.type().base() is null (e.g.
* "new Object[] {null}") we get the type from the parent (in this example, a
* NewArray of type Object[])
*/
public CAstNode visit(ArrayInit ai, WalkContext wc, Type t) {
TypeReference newTypeRef = fIdentityMapper.getTypeRef(t);
CAstNode[] eltNodes = new CAstNode[ai.elements().size() + 1];
int idx = 0;
eltNodes[idx++] = makeNode(wc, fFactory, ai, CAstNode.NEW, fFactory.makeConstant(newTypeRef), fFactory.makeConstant(ai
.elements().size()));
for (Iterator iter = ai.elements().iterator(); iter.hasNext(); idx++) {
Expr element = (Expr) iter.next();
if (element instanceof ArrayInit) {
eltNodes[idx] = visit((ArrayInit) element, wc, ((JavaArrayType) t).base());
} else {
eltNodes[idx] = walkNodes(element, wc);
}
if (eltNodes[idx] == null) {
Assertions.productionAssertion(eltNodes[idx] != null, element.toString());
}
}
return makeNode(wc, fFactory, ai, CAstNode.ARRAY_LITERAL, eltNodes);
}
public CAstNode visit(ArrayAccessAssign aaa, WalkContext wc) {
return processAssign(aaa, wc);
}
public CAstNode visit(FieldAssign fa, WalkContext wc) {
return processAssign(fa, wc);
}
public CAstNode visit(LocalAssign la, WalkContext wc) {
return processAssign(la, wc);
}
protected CAstNode processAssign(Node assign, CAstNode lhsCAstNode, Assign.Operator operator, Expr rhs, WalkContext wc) {
if (operator == Assign.ASSIGN) {
return makeNode(wc, fFactory, assign, CAstNode.ASSIGN, lhsCAstNode, walkNodes(rhs, wc));
} else {
CAstNode op =
makeNode(wc,
fFactory,
assign,
CAstNode.ASSIGN_PRE_OP,
lhsCAstNode,
walkNodes(rhs, wc),
mapAssignOperator(operator));
if (rhs.type().isLongOrLess() &&
(mapAssignOperator(operator)==CAstOperator.OP_DIV ||
mapAssignOperator(operator)==CAstOperator.OP_MOD))
{
Collection excTargets = wc.getCatchTargets(fDivByZeroType);
if (!excTargets.isEmpty()) {
for (Iterator iterator = excTargets.iterator(); iterator.hasNext();) {
Pair catchPair = (Pair) iterator.next();
wc.cfg().add(op, catchPair.snd, fDivByZeroType);
}
} else {
wc.cfg().add(op,
CAstControlFlowMap.EXCEPTION_TO_EXIT,
fDivByZeroType);
}
}
return op;
}
}
private CAstNode processAssign(Assign a, WalkContext wc) {
Expr lhs= a.left().type(a.type()); // PORT1.7 An Assign no longer has a lhs Expr per se; but you can ask it to materialize one...
WalkContext lvc = new AssignmentContext(wc);
return processAssign(a, walkNodes(lhs, lvc), a.operator(), a.right(), wc);
}
protected CAstOperator mapAssignOperator(Assign.Operator op) {
if (op == Assign.ADD_ASSIGN)
return CAstOperator.OP_ADD;
else if (op == Assign.BIT_AND_ASSIGN)
return CAstOperator.OP_BIT_AND;
else if (op == Assign.BIT_OR_ASSIGN)
return CAstOperator.OP_BIT_OR;
else if (op == Assign.BIT_XOR_ASSIGN)
return CAstOperator.OP_BIT_XOR;
else if (op == Assign.DIV_ASSIGN)
return CAstOperator.OP_DIV;
else if (op == Assign.MOD_ASSIGN)
return CAstOperator.OP_MOD;
else if (op == Assign.MUL_ASSIGN)
return CAstOperator.OP_MUL;
else if (op == Assign.SHL_ASSIGN)
return CAstOperator.OP_LSH;
else if (op == Assign.SHR_ASSIGN)
return CAstOperator.OP_RSH;
else if (op == Assign.SUB_ASSIGN)
return CAstOperator.OP_SUB;
else if (op == Assign.USHR_ASSIGN)
return CAstOperator.OP_URSH;
Assertions.UNREACHABLE("Unknown assignment operator");
return null;
}
public CAstNode visit(Binary b, WalkContext wc) {
Expr left = b.left();
Expr right = b.right();
Operator operator = b.operator();
if (operator.equals(Binary.COND_AND))
return makeNode(wc, fFactory, b, CAstNode.IF_EXPR, walkNodes(left, wc), walkNodes(right, wc), fFactory.makeConstant(false));
else if (operator.equals(Binary.COND_OR))
return makeNode(wc, fFactory, b, CAstNode.IF_EXPR, walkNodes(left, wc), fFactory.makeConstant(true), walkNodes(right, wc));
else {
Type leftType = left.type();
Type rightType = right.type();
if (leftType.isJavaPrimitive() && rightType.isJavaPrimitive()) {
CAstNode leftNode = walkNodes(left, wc);
CAstNode rightNode = walkNodes(right, wc);
try {
Type result = fTypeSystem.promote(leftType, rightType);
if (! result.typeEquals(leftType, fTypeSystem.emptyContext())) {
leftNode = makeNode(wc, fFactory, b, CAstNode.CAST, fFactory.makeConstant(getTypeDict().getCAstTypeFor(result)), leftNode, fFactory.makeConstant(getTypeDict().getCAstTypeFor(leftType)));
}
if (! result.typeEquals(rightType, fTypeSystem.emptyContext())) {
rightNode = makeNode(wc, fFactory, b, CAstNode.CAST, fFactory.makeConstant(getTypeDict().getCAstTypeFor(result)), rightNode, fFactory.makeConstant(getTypeDict().getCAstTypeFor(rightType)));
}
} catch (SemanticException e) {
}
CAstNode op = makeNode(wc, fFactory, b, CAstNode.BINARY_EXPR, mapBinaryOpcode(operator), leftNode, rightNode);
if (leftType.isLongOrLess() &&
rightType.isLongOrLess() &&
(mapBinaryOpcode(operator)==CAstOperator.OP_DIV ||
mapBinaryOpcode(operator)==CAstOperator.OP_MOD))
{
Collection excTargets = wc.getCatchTargets(fDivByZeroType);
if (!excTargets.isEmpty()) {
for (Iterator iterator = excTargets.iterator();
iterator.hasNext();)
{
Pair catchPair = (Pair) iterator.next();
wc.cfg().add(op, catchPair.snd, fDivByZeroType);
}
} else {
wc.cfg().add(op,
CAstControlFlowMap.EXCEPTION_TO_EXIT,
fDivByZeroType);
}
}
return op;
} else {
return makeNode(wc, fFactory, b, CAstNode.BINARY_EXPR, mapBinaryOpcode(operator), walkNodes(left, wc), walkNodes(right, wc));
}
}
}
@SuppressWarnings("unchecked")
private void handleThrowsFromCall(ProcedureInstance procedureInstance, Node callAstNode, WalkContext wc) {
/* there are no checked exceptions in X10
List<Type> throwTypes = procedureInstance.throwTypes();
for (Iterator<Type> iter = IteratorPlusOne.make(throwTypes.iterator(), fREType); iter.hasNext();) {
Type thrownType = (Type) iter.next();
Collection catchTargets = wc.getCatchTargets(thrownType);
for (Iterator targetIter = catchTargets.iterator(); targetIter.hasNext();) {
Pair catchTarget = (Pair) targetIter.next();
wc.cfg().add(callAstNode, catchTarget.snd, catchTarget.fst);
}
}
*/
}
public CAstNode visit(Call c, WalkContext wc) {
MethodInstance methodInstance = c.methodInstance();
boolean isStatic = methodInstance.flags().isStatic();
ContainerType methodOwner = methodInstance.container();
if (methodOwner.isArray()) {
List realOne = methodInstance.overrides(fTypeSystem.emptyContext());
Assertions.productionAssertion(realOne.size() == 2, "bad array method");
methodInstance = (MethodInstance) realOne.get(1);
methodOwner = methodInstance.container();
}
if (!methodOwner.isClass()) {
Assertions.productionAssertion(false, "owner " + methodOwner + " of " + methodInstance + " is not a class");
}
boolean isIntf = ((ClassType) methodOwner).flags().isInterface();
Receiver target = c.target();
boolean isSpecial = methodInstance.flags().isPrivate()
|| (target instanceof Special && ((Special) target).kind() == Special.SUPER);
CAstNode[] children = new CAstNode[2 + methodInstance.formalTypes().size()]; // including
// the
// MethodReference
int i = 0;
if (!isStatic)
children[i++] = walkNodes(target, wc);
else
children[i++] = makeNode(wc, fFactory, null, CAstNode.VOID);
if (children[0] == null) {
Assertions.productionAssertion(children[0] != null, "no receiver for " + methodInstance + " in " + wc.getEnclosingMethod());
}
MethodReference methodRef = fIdentityMapper.getMethodRef(methodInstance);
int dummyPC = 0; // Just want to wrap the kind of call; the "rear end"
// won't care about anything else...
CallSiteReference callSiteRef;
if (isStatic)
callSiteRef = CallSiteReference.make(dummyPC, methodRef, IInvokeInstruction.Dispatch.STATIC);
else if (isIntf)
callSiteRef = CallSiteReference.make(dummyPC, methodRef, IInvokeInstruction.Dispatch.INTERFACE);
else if (isSpecial)
callSiteRef = CallSiteReference.make(dummyPC, methodRef, IInvokeInstruction.Dispatch.SPECIAL);
else
callSiteRef = CallSiteReference.make(dummyPC, methodRef, IInvokeInstruction.Dispatch.VIRTUAL);
children[i++] = fFactory.makeConstant(callSiteRef);
for (Iterator iter = c.arguments().iterator(); iter.hasNext();) {
Expr arg = (Expr) iter.next();
children[i++] = walkNodes(arg, wc);
}
handleThrowsFromCall(methodInstance, c, wc);
CAstNode result = makeNode(wc, fFactory, c, CAstNode.CALL, children);
wc.cfg().map(c, result);
return result;
}
public CAstNode visit(ConstructorCall cc, WalkContext wc) {
ConstructorInstance ctorInstance = cc.constructorInstance();
ContainerType methodOwner = ctorInstance.container();
Assertions.productionAssertion(methodOwner.isClass());
MethodReference methodRef = fIdentityMapper.getMethodRef(ctorInstance);
int dummyPC = 0; // Just want to wrap the kind of call; the "rear end"
// won't care about anything else...
CallSiteReference callSiteRef = CallSiteReference.make(dummyPC, methodRef, IInvokeInstruction.Dispatch.SPECIAL);
CAstNode[] children = new CAstNode[1 + 1 + ctorInstance.formalTypes().size()]; // including
// the
// MethodReference
int i = 0;
CAstNode targetNode;
targetNode = (cc.kind() == ConstructorCall.THIS) ? makeNode(wc, fFactory, cc, CAstNode.THIS) : makeNode(wc, fFactory, cc,
CAstNode.SUPER);
children[i++] = targetNode;
children[i++] = fFactory.makeConstant(callSiteRef);
for (Iterator iter = cc.arguments().iterator(); iter.hasNext();) {
Expr arg = (Expr) iter.next();
children[i++] = walkNodes(arg, wc);
}
handleThrowsFromCall(ctorInstance, cc, wc);
CAstNode result = makeNode(wc, fFactory, cc, CAstNode.CALL, children);
wc.cfg().map(cc, result);
return result;
}
public CAstNode visit(Cast c, WalkContext wc) {
Expr arg = c.expr();
Type castedFrom = arg.type();
Type castedTo = c.castType().type();
// null can go into anything (e.g. in "((Foobar) null)" null can be assumed to be of type Foobar already)
if (castedFrom.isNull())
castedFrom = castedTo;
CAstNode ast = makeNode(wc, fFactory, c, CAstNode.CAST, fFactory.makeConstant(getTypeDict().getCAstTypeFor(castedTo)),
walkNodes(arg, wc),
fFactory.makeConstant(getTypeDict().getCAstTypeFor(castedFrom)));
Collection excTargets = wc.getCatchTargets(fCCEType);
if (!excTargets.isEmpty()) {
// connect ClassCastException exception edge to relevant catch targets
// (presumably only one)
for (Iterator iterator = excTargets.iterator(); iterator.hasNext();) {
Pair catchPair = (Pair) iterator.next();
wc.cfg().add(c, catchPair.snd, fCCEType);
}
} else {
// connect exception edge to exit
wc.cfg().add(c, CAstControlFlowMap.EXCEPTION_TO_EXIT, fCCEType);
}
wc.cfg().map(c, ast);
return ast;
}
public CAstNode visit(Conditional c, WalkContext wc) {
return makeNode(wc, fFactory, c, CAstNode.IF_EXPR, walkNodes(c.cond(), wc), walkNodes(c.consequent(), wc), walkNodes(c
.alternative(), wc));
}
public CAstNode visit(Instanceof io, WalkContext wc) {
return makeNode(wc, fFactory, io, CAstNode.INSTANCEOF, fFactory.makeConstant(getTypeDict().getCAstTypeFor(
io.compareType().type())), walkNodes(io.expr(), wc));
}
public CAstNode visit(BooleanLit bl, WalkContext wc) {
return fFactory.makeConstant(bl.value());
}
public CAstNode visit(ClassLit cl, WalkContext wc) {
Type litType = cl.typeNode().type();
String typeName = fIdentityMapper.typeToTypeID(litType);
return makeNode(wc, fFactory, cl, CAstNode.TYPE_LITERAL_EXPR, fFactory.makeConstant(typeName));
}
public CAstNode visit(FloatLit fl, WalkContext wc) {
return (fl.kind() == FloatLit.FLOAT) ? fFactory.makeConstant((float) fl.value()) : fFactory.makeConstant(fl.value());
}
public CAstNode visit(NullLit nl, WalkContext wc) {
return fFactory.makeConstant(null);
}
public CAstNode visit(CharLit cl, WalkContext wc) {
return fFactory.makeConstant(cl.value());
}
public CAstNode visit(IntLit il, WalkContext wc) {
return fFactory.makeConstant((int) il.value());
}
public CAstNode visit(StringLit sl, WalkContext wc) {
return fFactory.makeConstant(sl.value());
}
public CAstNode visit(New n, WalkContext wc) {
CAstEntity anonClass = null;
String newTypeNameStr;
TypeReference newTypeRef;
ConstructorInstance ctorInst = n.constructorInstance();
MethodReference ctorRef = fIdentityMapper.getMethodRef(ctorInst);
if (n.body() != null) {
fIdentityMapper.mapLocalAnonTypeToMethod(n.type().toClass(), wc.getEnclosingMethod());
anonClass = walkEntity(n, wc);
newTypeNameStr = anonClass.getType().getName();
TypeName newTypeName = TypeName.string2TypeName(newTypeNameStr);
Selector ctorSel = ctorRef.getSelector();
newTypeRef = TypeReference.findOrCreate(fClassLoaderRef, newTypeName);
ctorRef = MethodReference.findOrCreate(newTypeRef, ctorSel);
} else {
newTypeRef = fIdentityMapper.getTypeRef(n.type());
}
List/* <Expr> */args = n.arguments();
String tmpName = "ctor temp"; // this name is an illegal Java
// identifier
// new nodes with an explicit enclosing argument, e.g. "outer.new Inner()". They are mostly treated the same, except in JavaCAst2IRTranslator.doNewObject
CAstNode newNode;
Expr enclosing = n.qualifier();
if (enclosing != null) {
CAstNode encNode = walkNodes(enclosing, wc);
newNode = makeNode(wc, fFactory, n, CAstNode.NEW_ENCLOSING, fFactory.makeConstant(newTypeRef), encNode);
}
else
newNode = makeNode(wc, fFactory, n, CAstNode.NEW, fFactory.makeConstant(newTypeRef));
// end enclosing new stuff
if (n.body() != null)
wc.addScopedEntity(newNode, anonClass);
int dummyPC = 0; // Just want to wrap the kind of call; the "rear end"
// won't care about anything else...
CallSiteReference callSiteRef = CallSiteReference.make(dummyPC, ctorRef, IInvokeInstruction.Dispatch.SPECIAL);
CAstNode[] argNodes = new CAstNode[args.size() + 2]; // args + recvr
// + ctor ref
int idx = 0;
argNodes[idx++] = makeNode(wc, fFactory, n, CAstNode.VAR, fFactory.makeConstant(tmpName));
argNodes[idx++] = fFactory.makeConstant(callSiteRef);
for (Iterator iter = args.iterator(); iter.hasNext();) {
Expr arg = (Expr) iter.next();
argNodes[idx++] = walkNodes(arg, wc);
}
CAstNode callNode = makeNode(wc, fFactory, n, CAstNode.CALL, argNodes);
wc.cfg().map(n, callNode);
handleThrowsFromCall(ctorInst, n, wc);
return makeNode(wc, fFactory, n, CAstNode.LOCAL_SCOPE, makeNode(wc, fFactory, n, CAstNode.BLOCK_EXPR, makeNode(wc, fFactory,
n, CAstNode.DECL_STMT, fFactory.makeConstant(new InternalCAstSymbol(tmpName, true)), newNode), callNode, makeNode(wc,
fFactory, n, CAstNode.VAR, fFactory.makeConstant(tmpName))));
}
public CAstNode visit(NewArray na, WalkContext wc) {
Type newType = na.type();
ArrayInit ai = na.init();
Assertions.productionAssertion(newType.isArray());
if (ai != null) {
return visit(ai, wc, newType);
} else {
JavaArrayType arrayType = (JavaArrayType) newType;
TypeReference arrayTypeRef = fIdentityMapper.getTypeRef(arrayType);
List/* <Expr> */dims = na.dims();
CAstNode[] args = new CAstNode[dims.size() + 1];
int idx = 0;
args[idx++] = fFactory.makeConstant(arrayTypeRef);
for (Iterator iter = dims.iterator(); iter.hasNext();) {
Expr dimExpr = (Expr) iter.next();
args[idx++] = walkNodes(dimExpr, wc);
}
return makeNode(wc, fFactory, na, CAstNode.NEW, args);
}
}
public CAstNode visit(Special s, WalkContext wc) {
if (s.qualifier() != null) {
Type owningType = s.qualifier().type();
TypeReference owningTypeRef = fIdentityMapper.getTypeRef(owningType);
return makeNode(wc, fFactory, s, s.kind() == Special.THIS ? CAstNode.THIS : CAstNode.SUPER, fFactory
.makeConstant(owningTypeRef));
} else {
return makeNode(wc, fFactory, s, s.kind() == Special.THIS ? CAstNode.THIS : CAstNode.SUPER);
}
}
public CAstNode visit(Unary u, WalkContext wc) {
if (isAssignOp(u.operator())) {
WalkContext lvc = new AssignmentContext(wc);
if (u.operator().isPrefix())
return makeNode(wc, fFactory, u, CAstNode.ASSIGN_PRE_OP, walkNodes(u.expr(), lvc), fFactory.makeConstant(1),
mapUnaryOpcode(u.operator()));
else
return makeNode(wc, fFactory, u, CAstNode.ASSIGN_POST_OP, walkNodes(u.expr(), lvc), fFactory.makeConstant(1),
mapUnaryOpcode(u.operator()));
} else if (u.operator() == Unary.POS) // drop useless unary plus
// operator
return walkNodes(u.expr(), wc);
else if (u.operator() == Unary.NEG) {
CAstNode zero;
if (u.expr().type().isLongOrLess())
zero = fFactory.makeConstant(0L);
else
zero = fFactory.makeConstant(0.0);
return makeNode(wc, fFactory, u, CAstNode.BINARY_EXPR, CAstOperator.OP_SUB, zero, walkNodes(u.expr(), wc));
} else
return makeNode(wc, fFactory, u, CAstNode.UNARY_EXPR, mapUnaryOpcode(u.operator()), walkNodes(u.expr(), wc));
}
protected boolean isAssignOp(Unary.Operator operator) {
return operator == Unary.POST_DEC || operator == Unary.POST_INC || operator == Unary.PRE_DEC || operator == Unary.PRE_INC;
}
public CAstNode visit(ArrayAccess aa, WalkContext wc) {
TypeReference eltTypeRef = fIdentityMapper.getTypeRef(aa.type());
hookUpNPETargets(aa, wc);
CAstNode n = makeNode(wc, fFactory, aa, CAstNode.ARRAY_REF, walkNodes(aa.array(), wc), fFactory.makeConstant(eltTypeRef),
walkNodes(aa.index(), wc));
wc.cfg().map(aa, n);
return n;
}
protected void hookUpNPETargets(Node n, WalkContext wc) {
Collection excTargets = wc.getCatchTargets(fNPEType);
if (!excTargets.isEmpty()) {
// connect NPE exception edge to relevant catch targets
// (presumably only one)
for (Iterator iterator = excTargets.iterator(); iterator.hasNext();) {
Pair catchPair = (Pair) iterator.next();
wc.cfg().add(n, catchPair.snd, fNPEType);
}
} else {
// connect exception edge to exit
wc.cfg().add(n, CAstControlFlowMap.EXCEPTION_TO_EXIT, fNPEType);
}
}
public CAstNode visit(Field f, WalkContext wc) {
Receiver target = f.target();
Type targetType = target.type();
if (targetType.isArray()) {
Assertions.productionAssertion(f.name().toString().equals("length"));
return makeNode(wc, fFactory, f, CAstNode.ARRAY_LENGTH, walkNodes(target, wc));
}
FieldInstance fi = f.fieldInstance();
FieldReference fieldRef = fIdentityMapper.getFieldRef(fi);
CAstNode targetNode = walkNodes(target, wc);
if (fi.flags().isStatic()) {
// JLS says: evaluate the target of the field ref and throw it away.
// Hence the following block expr, whose 2 children are the target
// evaluation
// followed by the OBJECT_REF with a null target child (which the
// "back-end"
// CAst -> IR translator interprets as a static ref).
if (fi.isConstant()) {
return makeNode(wc, fFactory, f, CAstNode.BLOCK_EXPR, targetNode, // can have side effects!
translateConstant(fi.constantValue()));
} else {
return makeNode(wc, fFactory, f, CAstNode.BLOCK_EXPR, targetNode, makeNode(wc, fFactory, f, CAstNode.OBJECT_REF,
makeNode(wc, fFactory, null, CAstNode.VOID), fFactory.makeConstant(fieldRef)));
}
} else {
Collection excTargets = wc.getCatchTargets(fNPEType);
if (!excTargets.isEmpty()) {
// connect NPE exception edge to relevant catch targets
// (presumably only one)
for (Iterator iterator = excTargets.iterator(); iterator.hasNext();) {
Pair catchPair = (Pair) iterator.next();
wc.cfg().add(f, catchPair.snd, fNPEType);
}
} else {
// connect exception edge to exit
wc.cfg().add(f, CAstControlFlowMap.EXCEPTION_TO_EXIT, fNPEType);
}
CAstNode refNode = makeNode(wc, fFactory, f, CAstNode.OBJECT_REF, targetNode, fFactory.makeConstant(fieldRef));
wc.cfg().map(f, refNode);
if (fi.isConstant()) {
return makeNode(wc, fFactory, f, CAstNode.BLOCK_EXPR, refNode, // can have side effects!
translateConstant(fi.constantValue()));
} else {
return refNode;
}
}
}
public CAstNode visit(Local l, WalkContext wc) {
return makeNode(wc, fFactory, l, CAstNode.VAR, fFactory.makeConstant(l.name().id().toString()));
}
public CAstNode visit(ClassBody cb, WalkContext wc) {
Assertions.UNREACHABLE("walkNodes.ASTTraverser.visit(ClassBody)");
return null;
}
public CAstNode visit(ClassDecl cd, WalkContext wc) {
Assertions.UNREACHABLE("walkNodes.ASTTraverser.visit(ClassDecl)");
return null;
}
public CAstNode visit(Initializer i, WalkContext wc) {
// Perhaps this is invoked from within the ConstructorDecl visit()
// method...
return walkNodes(i.body(), wc);
}
public CAstNode visit(Assert a, WalkContext wc) {
return makeNode(wc, fFactory, a, CAstNode.ASSERT, walkNodes(a.cond(), wc));
}
public CAstNode visit(Branch b, WalkContext wc) {
Node target = null;
Id labelNode = b.labelNode();
String labelStr = labelNode != null ? labelNode.id().toString() : null;
if (b.kind() == Branch.BREAK) {
target = wc.getBreakFor(labelStr);
} else {
target = wc.getContinueFor(labelStr);
}
Assertions.productionAssertion(target != null);
CAstNode result = makeNode(wc, fFactory, b, CAstNode.GOTO);
wc.cfg().map(b, result);
wc.cfg().add(b, target, null);
return result;
}
public CAstNode visit(Block b, WalkContext wc) {
CAstNode[] stmtNodes = new CAstNode[b.statements().size()];
int idx = 0;
for (Iterator iter = b.statements().iterator(); iter.hasNext(); idx++) {
Stmt s = (Stmt) iter.next();
stmtNodes[idx] = walkNodes(s, wc);
}
return makeNode(wc, fFactory, b, CAstNode.LOCAL_SCOPE, makeNode(wc, fFactory, b, CAstNode.BLOCK_STMT, stmtNodes));
}
public CAstNode visit(StmtSeq seq, WalkContext wc) {
CAstNode[] stmtNodes = new CAstNode[seq.statements().size()];
int idx = 0;
for (Iterator iter = seq.statements().iterator(); iter.hasNext(); idx++) {
Stmt s = (Stmt) iter.next();
stmtNodes[idx] = walkNodes(s, wc);
}
return makeNode(wc, fFactory, seq, CAstNode.BLOCK_STMT, stmtNodes);
}
public CAstNode visit(SwitchBlock sb, WalkContext wc) {
CAstNode[] stmtNodes = new CAstNode[sb.statements().size()];
int idx = 0;
for (Iterator iter = sb.statements().iterator(); iter.hasNext(); idx++) {
Stmt s = (Stmt) iter.next();
stmtNodes[idx] = walkNodes(s, wc);
}
return makeNode(wc, fFactory, sb, CAstNode.BLOCK_STMT, stmtNodes);
}
public CAstNode visit(Catch c, WalkContext wc) {
Block body = c.body();
Formal f = c.formal();
CAstNode excDecl = makeNode(wc, fFactory, c, CAstNode.CATCH, fFactory.makeConstant(f.name().id().toString()), walkNodes(body, wc));
CAstNode localScope = makeNode(wc, fFactory, c, CAstNode.LOCAL_SCOPE, excDecl);
wc.cfg().map(c, excDecl);
wc.getNodeTypeMap().add(excDecl, wc.getTypeDictionary().getCAstTypeFor(c.catchType()));
return localScope;
}
public CAstNode visit(If i, WalkContext wc) {
return makeNode(wc, fFactory, i, CAstNode.IF_STMT, walkNodes(i.cond(), wc), walkNodes(i.consequent(), wc), walkNodes(i
.alternative(), wc));
}
public CAstNode visit(Labeled l, WalkContext wc) {
Node breakTarget = makeBreakTarget(l);
Node stmt = l.statement();
while (stmt instanceof Block) {
stmt = (Node) ((Block) stmt).statements().iterator().next();
}
wc.getLabelMap().put(stmt, l.labelNode().id().toString());
CAstNode result;
if (! (l.statement() instanceof Empty)) {
WalkContext child = new BreakContext(wc, l.labelNode().id().toString(), breakTarget);
result =
makeNode(wc, fFactory, l, CAstNode.BLOCK_STMT,
makeNode(wc, fFactory, l, CAstNode.LABEL_STMT, fFactory.makeConstant(l.labelNode().id().toString()), walkNodes(l.statement(), child)),
walkNodes(breakTarget, wc));
} else {
result =
makeNode(wc, fFactory, l, CAstNode.LABEL_STMT, fFactory.makeConstant(l.labelNode().id().toString()), walkNodes(l.statement(), wc));
}
wc.cfg().map(l, result);
wc.getLabelMap().remove(stmt);
return result;
}
public CAstNode visit(LocalClassDecl lcd, WalkContext wc) {
fIdentityMapper.mapLocalAnonTypeToMethod(lcd.decl().classDef().asType(), wc.getEnclosingMethod());
CAstEntity classEntity = walkEntity(lcd.decl(), wc);
final CAstNode lcdNode = makeNode(wc, fFactory, lcd, CAstNode.EMPTY);
wc.addScopedEntity(lcdNode, classEntity);
return lcdNode;
}
protected Node makeBreakTarget(Node loop) {
return fNodeFactory.Labeled(Position.COMPILER_GENERATED,
fNodeFactory.Id(Position.COMPILER_GENERATED, "breakLabel" + loop.position().toString().replace('.', '_')),
fNodeFactory.Empty(Position.COMPILER_GENERATED));
}
protected Node makeContinueTarget(Node loop) {
return fNodeFactory.Labeled(Position.COMPILER_GENERATED,
fNodeFactory.Id(Position.COMPILER_GENERATED, "continueLabel" + loop.position().toString().replace('.', '_')),
fNodeFactory.Empty(Position.COMPILER_GENERATED));
}
public CAstNode visit(Do d, WalkContext wc) {
Node breakTarget = makeBreakTarget(d);
Node continueTarget = makeContinueTarget(d);
String loopLabel = (String) wc.getLabelMap().get(d);
CAstNode continueNode = walkNodes(continueTarget, wc);
CAstNode breakBody = walkNodes(breakTarget, wc);
WalkContext lc = new LoopContext(wc, loopLabel, breakTarget, continueTarget);
CAstNode loopBody = walkNodes(d.body(), lc);
if (replicateForDoLoops) {
CAstRewriter.Rewrite x = (new CAstCloner(fFactory, false)).copy(loopBody, wc.cfg(), wc.pos(), wc.getNodeTypeMap(), null);
CAstNode otherBody = x.newRoot();
wc.cfg().addAll(x.newCfg());
wc.pos().addAll(x.newPos());
wc.getNodeTypeMap().addAll(x.newTypes());
return makeNode(wc, fFactory, d, CAstNode.BLOCK_STMT,
loopBody,
makeNode(wc, fFactory, d, CAstNode.LOOP,
walkNodes(d.cond(), wc),
makeNode(wc, fFactory, d, CAstNode.BLOCK_STMT, otherBody, continueNode)),
breakBody);
} else {
Node header = fNodeFactory.Empty(Position.COMPILER_GENERATED);
CAstNode loopGoto = makeNode(wc, fFactory, d, CAstNode.IFGOTO, walkNodes(d.cond(), wc));
wc.cfg().map(loopGoto, loopGoto);
wc.cfg().add(loopGoto, header, Boolean.TRUE);
return makeNode(wc, fFactory, d, CAstNode.BLOCK_STMT,
walkNodes(header, wc),
makeNode(wc, fFactory, d, CAstNode.BLOCK_STMT, loopBody, continueNode),
loopGoto,
breakBody);
}
}
public CAstNode visit(For f, WalkContext wc) {
Node breakTarget = makeBreakTarget(f);
Node continueTarget = makeContinueTarget(f);
String loopLabel = (String) wc.getLabelMap().get(f);
WalkContext lc = new LoopContext(wc, loopLabel, breakTarget, continueTarget);
CAstNode[] inits = new CAstNode[f.inits().size()];
for (int i = 0; i < inits.length; i++) {
inits[i] = walkNodes((Node) f.inits().get(i), wc);
}
CAstNode[] iters = new CAstNode[f.iters().size()];
for (int i = 0; i < iters.length; i++) {
iters[i] = walkNodes((Node) f.iters().get(i), wc);
}
CAstNode initsBlock = makeNode(wc, fFactory, f, CAstNode.BLOCK_STMT, inits);
CAstNode itersBlock = makeNode(wc, fFactory, f, CAstNode.BLOCK_STMT, iters);
return makeNode(wc, fFactory, f, CAstNode.BLOCK_STMT, initsBlock, makeNode(wc, fFactory, f, CAstNode.LOOP, walkNodes(
f.cond(), wc), makeNode(wc, fFactory, f, CAstNode.BLOCK_STMT, walkNodes(f.body(), lc), walkNodes(continueTarget, wc),
itersBlock)), walkNodes(breakTarget, wc));
}
public CAstNode visit(While w, WalkContext wc) {
Expr c = w.cond();
Stmt b = w.body();
Node breakTarget = makeBreakTarget(w);
Node continueTarget = makeContinueTarget(w);
String loopLabel = (String) wc.getLabelMap().get(w);
LoopContext lc = new LoopContext(wc, loopLabel, breakTarget, continueTarget);
/*
* The following loop is created sligtly differently than in jscore. It doesn't have a specific target for continue.
*/
return makeNode(wc, fFactory, w, CAstNode.BLOCK_STMT, makeNode(wc, fFactory, w, CAstNode.LOOP, walkNodes(c, wc), makeNode(wc,
fFactory, w, CAstNode.BLOCK_STMT, walkNodes(b, lc), walkNodes(continueTarget, wc))), walkNodes(breakTarget, wc));
}
public CAstNode visit(Switch s, WalkContext wc) {
Node breakLabel = fNodeFactory.Labeled(s.position(),
fNodeFactory.Id(s.position(), "switchBreakLabel" + s.position().toString().replace('.', '_')),
fNodeFactory.Empty(s.position()));
CAstNode breakAst = walkNodes(breakLabel, wc);
String loopLabel = (String) wc.getLabelMap().get(s);
WalkContext child = new BreakContext(wc, loopLabel, breakLabel);
Expr cond = s.expr();
List cases = s.elements();
// First compute the control flow edges for the various case labels
for (int i = 0; i < cases.size(); i++) {
SwitchElement se = (SwitchElement) cases.get(i);
if (se instanceof Case) {
Case c = (Case) se;
if (c.isDefault())
wc.cfg().add(s, c, CAstControlFlowMap.SWITCH_DEFAULT);
else
wc.cfg().add(s, c, fFactory.makeConstant(c.value()));
}
}
CAstNode[] caseNodes = new CAstNode[cases.size()];
// Now produce the CAst representation for each case
int idx = 0;
for (Iterator iter = cases.iterator(); iter.hasNext(); idx++) {
SwitchElement se = (SwitchElement) iter.next();
caseNodes[idx] = walkNodes(se, child);
}
// Now produce the switch stmt itself
CAstNode switchAst = makeNode(wc, fFactory, s, CAstNode.SWITCH, walkNodes(cond, wc), makeNode(wc, fFactory, s,
CAstNode.BLOCK_STMT, caseNodes));
wc.cfg().map(s, switchAst);
// Finally, wrap the entire switch in a block so that we have a
// well-defined place to 'break' to.
return makeNode(wc, fFactory, s, CAstNode.BLOCK_STMT, switchAst, breakAst);
}
public CAstNode visit(Try t, WalkContext wc) {
List catchBlocks = t.catchBlocks();
Block finallyBlock = t.finallyBlock();
Block tryBlock = t.tryBlock();
// try/finally
if (catchBlocks.isEmpty()) {
return makeNode(wc, fFactory, t, CAstNode.UNWIND, walkNodes(tryBlock, wc), walkNodes(finallyBlock, wc));
// try/catch/[finally]
} else {
TryCatchContext tc = new TryCatchContext(wc, t, fTypeSystem.emptyContext());
CAstNode tryNode = walkNodes(tryBlock, tc);
for (Iterator iter = catchBlocks.iterator(); iter.hasNext();) {
tryNode = makeNode(wc, fFactory, t, CAstNode.TRY, tryNode, walkNodes((Catch) iter.next(), wc));
}
// try/catch
if (finallyBlock == null) {
return tryNode;
// try/catch/finally
} else {
return makeNode(wc, fFactory, t, CAstNode.UNWIND, tryNode, walkNodes(finallyBlock, wc));
}
}
}
public CAstNode visit(Empty e, WalkContext wc) {
CAstNode result = makeNode(wc, fFactory, e, CAstNode.EMPTY);
wc.cfg().map(e, result);
return result;
}
public CAstNode visit(Eval e, WalkContext wc) {
return walkNodes(e.expr(), wc);
}
public CAstNode visit(LocalDecl ld, WalkContext wc) {
Expr init = ld.init();
Type type = ld.declType();
CAstNode initNode;
if (init == null) {
if (type.isLongOrLess())
initNode = fFactory.makeConstant(0);
else if (type.isDouble() || type.isFloat())
initNode = fFactory.makeConstant(0.0);
else
initNode = fFactory.makeConstant(null);
} else if (init instanceof ArrayInit)
initNode = visit((ArrayInit) init, wc, type);
else
initNode = walkNodes(init, wc);
Object defaultValue;
if (type.isLongOrLess())
defaultValue = new Integer(0);
else if (type.isDouble() || type.isFloat())
defaultValue = new Double(0.0);
else
defaultValue = CAstSymbol.NULL_DEFAULT_VALUE;
boolean isFinal = ld.flags().flags().isFinal();
return makeNode(wc, fFactory, ld, CAstNode.DECL_STMT, fFactory.makeConstant(new CAstSymbolImpl(ld.name().id().toString(), isFinal,
defaultValue)), initNode);
}
public CAstNode visit(Return r, WalkContext wc) {
Expr retExpr = r.expr();
if (retExpr == null)
return makeNode(wc, fFactory, r, CAstNode.RETURN);
else
return makeNode(wc, fFactory, r, CAstNode.RETURN, walkNodes(retExpr, wc));
}
public CAstNode visit(Case c, WalkContext wc) {
CAstNode label = makeNode(wc, fFactory, c, CAstNode.LABEL_STMT, fFactory.makeConstant(c.value()));
wc.cfg().map(c, label);
return label;
}
public CAstNode visit(Throw t, WalkContext wc) {
CAstNode result = makeNode(wc, fFactory, t, CAstNode.THROW, walkNodes(t.expr(), wc));
Type label = t.expr().type();
wc.cfg().map(t, result);
Collection/* <Pair<Type,Node>> */catchNodes = wc.getCatchTargets(label);
for (Iterator iter = catchNodes.iterator(); iter.hasNext();) {
Pair/* <Type,Node> */catchNode = (Pair/* <Type,Node> */) iter.next();
wc.cfg().add(t, catchNode.snd, catchNode.fst);
}
return result;
}
public CAstNode visit(Formal f, WalkContext wc) {
return makeNode(wc, fFactory, f, CAstNode.VAR, fFactory.makeConstant(f.name().id().toString()));
}
}
protected static final class CompilationUnitEntity implements CAstEntity {
private final String fName;
private final Collection<CAstEntity> fTopLevelDecls;
public CompilationUnitEntity(SourceFile file, List<CAstEntity> topLevelDecls) {
fName = (file.package_() == null) ? "" : file.package_().package_().get().fullName().toString().replace('.', '/');
fTopLevelDecls = topLevelDecls;
}
public int getKind() {
return FILE_ENTITY;
}
public String getName() {
return fName;
}
public String getSignature() {
Assertions.UNREACHABLE();
return null;
}
public String[] getArgumentNames() {
return new String[0];
}
public CAstNode[] getArgumentDefaults() {
return new CAstNode[0];
}
public int getArgumentCount() {
return 0;
}
public Map<CAstNode, Collection<CAstEntity>> getAllScopedEntities() {
return Collections.singletonMap(null, fTopLevelDecls);
}
public Iterator getScopedEntities(CAstNode construct) {
Assertions.UNREACHABLE("CompilationUnitEntity asked for AST-related entities, but it has no AST.");
return null;
}
public CAstNode getAST() {
return null;
}
public CAstControlFlowMap getControlFlow() {
Assertions.UNREACHABLE("CompilationUnitEntity.getControlFlow()");
return null;
}
public CAstSourcePositionMap getSourceMap() {
Assertions.UNREACHABLE("CompilationUnitEntity.getSourceMap()");
return null;
}
public CAstSourcePositionMap.Position getPosition() {
Assertions.UNREACHABLE("CompilationUnitEntity.getPosition()");
return null;
}
public CAstNodeTypeMap getNodeTypeMap() {
Assertions.UNREACHABLE("CompilationUnitEntity.getNodeTypeMap()");
return null;
}
public Collection getQualifiers() {
return Collections.EMPTY_LIST;
}
public CAstType getType() {
Assertions.UNREACHABLE("CompilationUnitEntity.getType()");
return null;
}
}
public class PolyglotJavaType implements JavaType {
protected final CAstTypeDictionary fDict;
protected final TypeSystem fSystem;
protected final ClassType fType;
private Collection<CAstType> fSuperTypes = null;
public PolyglotJavaType(ClassType type, CAstTypeDictionary dict, TypeSystem system) {
super();
fDict = dict;
fSystem = system;
fType = type;
}
public String getName() {
// TODO Will the IdentityMapper do the right thing for anonymous classes?
// If so, we can delete most of the following logic...
if (fType.isLocal() || fType.isAnonymous()) {
return fIdentityMapper.anonLocalTypeToTypeID(fType);
} else
return fIdentityMapper.getTypeRef(fType).getName().toString();
}
public Collection getSupertypes() {
if (fSuperTypes == null) {
buildSuperTypes();
}
return fSuperTypes;
}
private void buildSuperTypes() {
// TODO this is a source entity, but it might actually be the root type
// (Object), so assume # intfs + 1
Type superType;
if (fType.superClass() == null) {
superType = fSystem.Any(); // fSystem.Object() MUST be the root of the class hierarchy
} else {
superType = fType.superClass();
}
int N = fType.interfaces().size() + 1;
fSuperTypes = new ArrayList<CAstType>(N);
// Following assumes that no one can call getSupertypes() before we have
// created CAstType's for every type in the program being analyzed.
if (superType != null) {
fSuperTypes.add(fDict.getCAstTypeFor(superType));
}
for (Iterator iter = fType.interfaces().iterator(); iter.hasNext(); ) {
Type t = (Type) iter.next();
if (t instanceof ClassType) {
ClassType classType = (ClassType) t;
// [DC] seems that this no-longer applies in an Object-less X10
//if (classType == fSystem.Object()) {
// continue; // Skip fSystem.Object() as a super-interface; it really MUST be a class as far as WALA is concerned
//}
}
fSuperTypes.add(fDict.getCAstTypeFor(t));
}
}
public Collection<CAstQualifier> getQualifiers() {
return mapFlagsToQualifiers(fType.flags());
}
public boolean isInterface() {
// [DC] seems that this no-longer applies in an Object-less X10
//if (fType == fSystem.Object()) {
// return false; // fSystem.Object() MUST be a class, as far as WALA is concerned
//}
return fType.flags().isInterface();
}
}
protected abstract static class CodeBodyEntity implements CAstEntity {
private final Map<CAstNode, Collection<CAstEntity>> fEntities;
public CodeBodyEntity(Map<CAstNode, CAstEntity> entities) {
fEntities = new LinkedHashMap<CAstNode, Collection<CAstEntity>>();
for (Iterator keys = entities.keySet().iterator(); keys.hasNext();) {
CAstNode key = (CAstNode) keys.next();
fEntities.put(key, Collections.singleton(entities.get(key)));
}
}
public Map<CAstNode, Collection<CAstEntity>> getAllScopedEntities() {
return Collections.unmodifiableMap(fEntities);
}
public Iterator getScopedEntities(CAstNode construct) {
if (fEntities.containsKey(construct)) {
return (fEntities.get(construct)).iterator();
} else {
return EmptyIterator.instance();
}
}
public String getSignature() {
return Util.methodEntityToSelector(this).toString();
}
}
protected final class ClassEntity implements CAstEntity {
@SuppressWarnings("unused")
private final ClassContext fContext;
private final ClassType fCT;
private final String fName;
private final Collection<CAstEntity> fEntities;
private final CAstSourcePositionMap.Position sourcePosition;
private ClassEntity(ClassContext context, List<CAstEntity> entities, ClassDecl cd, Position p) {
this(context, entities, cd.classDef().asType(), cd.name().id().toString(), p);
}
private ClassEntity(ClassContext context, List<CAstEntity> entities, ClassType ct, String name, Position p) {
fContext = context;
this.fEntities = entities;
fCT = ct;
fName = name;
sourcePosition = makePosition(p);
}
public int getKind() {
return TYPE_ENTITY;
}
public String getName() {
return fName; // unqualified?
}
public String getSignature() {
return "L" + fName.replace('.', '/') + ";";
}
public String[] getArgumentNames() {
return new String[0];
}
public CAstNode[] getArgumentDefaults() {
return new CAstNode[0];
}
public int getArgumentCount() {
return 0;
}
public CAstNode getAST() {
// This entity has no AST nodes, really.
return null;
}
public Map<CAstNode, Collection<CAstEntity>> getAllScopedEntities() {
return Collections.singletonMap(null, fEntities);
}
public Iterator getScopedEntities(CAstNode construct) {
Assertions.UNREACHABLE("Non-AST-bearing entity (ClassEntity) asked for scoped entities related to a given AST node");
return null;
}
public CAstControlFlowMap getControlFlow() {
// This entity has no AST nodes, really.
return null;
}
public CAstSourcePositionMap getSourceMap() {
// This entity has no AST nodes, really.
return null;
}
public CAstSourcePositionMap.Position getPosition() {
return sourcePosition;
}
public CAstNodeTypeMap getNodeTypeMap() {
// This entity has no AST nodes, really.
return new CAstNodeTypeMap() {
public CAstType getNodeType(CAstNode node) {
throw new UnsupportedOperationException();
}
public Collection<CAstNode> getMappedNodes() {
throw new UnsupportedOperationException();
}
};
}
public Collection getQualifiers() {
// [DC] seems this does not apply in an object-less X10
//if (fCT == fTypeSystem.Object()) { // pretend the root of the hierarchy is always a class
// return mapFlagsToQualifiers(fCT.flags().clear(Flags.INTERFACE));
//}
return mapFlagsToQualifiers(fCT.flags());
}
public CAstType getType() {
return new PolyglotJavaType(fCT, getTypeDict(), fTypeSystem);
}
@Override
public String toString() {
return fCT.fullName().toString();
}
}
protected final class ProcedureEntity extends CodeBodyEntity implements JavaProcedureEntity {
private final CAstNode fPdast;
private final TypeSystem fSystem;
private final Type declaringType;
private final CodeInstance fPd;
private final MethodContext fMc;
private final String[] argumentNames;
public ProcedureEntity(CAstNode pdast, TypeSystem system, CodeInstance pd, Type declaringType, String[] argumentNames,
Map<CAstNode, CAstEntity> entities, MethodContext mc) {
super(entities);
fPdast = pdast;
fSystem = system;
fPd = pd;
this.declaringType = declaringType;
this.argumentNames = argumentNames;
fMc = mc;
}
public ProcedureEntity(CAstNode pdast, TypeSystem system, CodeInstance pd, String[] argumentNames,
Map<CAstNode, CAstEntity> entities, MethodContext mc) {
//PORT1.7 used to be this(pdast, system, pd, ((MemberInstance) pd).container(), argumentNames, entities, mc);
this(pdast, system, pd, ((MemberDef) pd.def()).container().get(), argumentNames, entities, mc);
}
private List formalTypes() {
if (fPd instanceof ProcedureInstance) {
return ((ProcedureInstance) fPd).formalTypes();
} else {
return Collections.EMPTY_LIST;
}
}
public String toString() {
return fPd.toString();
}
public int getKind() {
return CAstEntity.FUNCTION_ENTITY;
}
public String getName() {
if (fPd instanceof ConstructorInstance) {
return MethodReference.initAtom.toString();
} else {
if (fPd instanceof InitializerInstance) {
return MethodReference.clinitName.toString();
} else {
Assertions.productionAssertion(fPd instanceof MethodInstance);
return ((MethodInstance) fPd).name().toString();
}
}
}
public String[] getArgumentNames() {
return argumentNames;
}
public CAstNode[] getArgumentDefaults() {
return new CAstNode[0];
}
private Flags getFlags() {
// PORT1.7
if (fPd instanceof ProcedureInstance) {
return ((MemberDef) fPd.def()).flags();
}
return Flags.NONE;
}
private boolean isStatic() {
// PORT1.7
if (fPd instanceof ProcedureInstance) {
return ((MemberDef) fPd.def()).flags().isStatic();
} else if (fPd instanceof InitializerInstance) {
return ((InitializerInstance) fPd).def().flags().isStatic();
}
return false;
}
public int getArgumentCount() {
return isStatic() ? formalTypes().size() : formalTypes().size() + 1;
}
public CAstNode getAST() {
return fPdast;
}
public CAstControlFlowMap getControlFlow() {
return fMc.cfg();
}
public CAstSourcePositionMap getSourceMap() {
return fMc.pos();
}
public CAstSourcePositionMap.Position getPosition() {
return getSourceMap().getPosition(fPdast);
}
public CAstNodeTypeMap getNodeTypeMap() {
return fMc.getNodeTypeMap();
}
public Collection getQualifiers() {
return mapFlagsToQualifiers(getFlags());
}
public CAstType getType() {
return new CAstType.Method() {
private Collection<CAstType> fExceptionTypes = null;
private List<CAstType> fParameterTypes = null;
public CAstType getReturnType() {
return fMc.getTypeDictionary().getCAstTypeFor(
(fPd instanceof MethodInstance) ? ((MethodInstance) fPd).returnType() : fSystem.Void());
}
public List getArgumentTypes() {
if (fParameterTypes == null) {
final List formalTypes = formalTypes();
fParameterTypes = new ArrayList<CAstType>(formalTypes.size());
for (Iterator iter = formalTypes.iterator(); iter.hasNext();) {
fParameterTypes.add(fMc.getTypeDictionary().getCAstTypeFor((Type) iter.next()));
}
}
return fParameterTypes;
}
public String getName() {
Assertions.UNREACHABLE("CAstType.FunctionImpl#getName() called???");
return "?";
}
public Collection getSupertypes() {
Assertions.UNREACHABLE("CAstType.FunctionImpl#getSupertypes() called???");
return null;
}
public Collection/* <CAstType> */getExceptionTypes() {
return Collections.EMPTY_LIST;
/* there are no checked exceptions in X10
if (fExceptionTypes == null) {
fExceptionTypes = new LinkedHashSet<CAstType>();
}
return fExceptionTypes;
*/
}
public int getArgumentCount() {
return formalTypes().size();
}
public CAstType getDeclaringType() {
return getTypeDict().getCAstTypeFor(declaringType);
}
};
}
}
protected final class FieldEntity implements CAstEntity {
private final FieldInstance fFI;
private final WalkContext fContext;
private FieldEntity(FieldDecl fd, WalkContext context) {
super();
fFI = fd.fieldDef().asInstance();
fContext = context;
}
public int getKind() {
return CAstEntity.FIELD_ENTITY;
}
public String getName() {
return fFI.name().toString();
}
public String getSignature() {
return fFI.name() + fIdentityMapper.typeToTypeID(fFI.type());
}
public String[] getArgumentNames() {
return new String[0];
}
public CAstNode[] getArgumentDefaults() {
return new CAstNode[0];
}
public int getArgumentCount() {
return 0;
}
public Iterator getScopedEntities(CAstNode construct) {
return EmptyIterator.instance();
}
public Map<CAstNode, Collection<CAstEntity>> getAllScopedEntities() {
return Collections.emptyMap();
}
public CAstNode getAST() {
// No AST for a field decl; initializers folded into
// constructor processing...
return null;
}
public CAstControlFlowMap getControlFlow() {
// No AST for a field decl; initializers folded into
// constructor processing...
return null;
}
public CAstSourcePositionMap getSourceMap() {
// No AST for a field decl; initializers folded into
// constructor processing...
return null;
}
public CAstSourcePositionMap.Position getPosition() {
return makePosition(fFI.position());
}
public CAstNodeTypeMap getNodeTypeMap() {
// No AST for a field decl; initializers folded into
// constructor processing...
return null;
}
public Collection getQualifiers() {
return mapFlagsToQualifiers(fFI.flags());
}
public CAstType getType() {
return fContext.getTypeDictionary().getCAstTypeFor(fFI.type());
}
}
protected static class DelegatingContext implements WalkContext {
private final WalkContext parent;
public WalkContext getParent() {
return parent;
}
protected DelegatingContext(WalkContext parent) {
this.parent = parent;
}
public void addScopedEntity(CAstNode node, CAstEntity e) {
parent.addScopedEntity(node, e);
}
// public Map/*<CAstNode,CAstEntity>*/ getScopedEntities() {
// return parent.getScopedEntities();
// }
public CAstControlFlowRecorder cfg() {
return parent.cfg();
}
public CAstSourcePositionRecorder pos() {
return parent.pos();
}
public CAstNodeTypeMapRecorder getNodeTypeMap() {
return parent.getNodeTypeMap();
}
public Collection<Pair<Type, Object>> getCatchTargets(Type label) {
return parent.getCatchTargets(label);
}
public Node getContinueFor(String label) {
return parent.getContinueFor(label);
}
public Node getBreakFor(String label) {
return parent.getBreakFor(label);
}
public Node getFinally() {
return parent.getFinally();
}
public CodeInstance getEnclosingMethod() {
return parent.getEnclosingMethod();
}
public Type getEnclosingType() {
return parent.getEnclosingType();
}
public CAstTypeDictionary getTypeDictionary() {
return parent.getTypeDictionary();
}
public List<ClassMember> getStaticInitializers() {
return parent.getStaticInitializers();
}
public List<ClassMember> getInitializers() {
return parent.getInitializers();
}
public Map<Node, String> getLabelMap() {
return parent.getLabelMap();
}
public boolean needLVal() {
return parent.needLVal();
}
}
public class ClassContext extends DelegatingContext {
// private final ClassDecl cd;
private final Type type;
private List<ClassMember>/* <Initializer+FieldDecl> */fInitializers = new ArrayList<ClassMember>();
private List<ClassMember>/* <Initializer+FieldDecl> */fStaticInitializers = new ArrayList<ClassMember>();
private List<CAstEntity> fChildren;
public ClassContext(Type type, List<CAstEntity> entities, WalkContext parent) {
super(parent);
this.type = type;
fChildren = entities;
}
public void addScopedEntity(CAstNode node, CAstEntity e) {
Assertions.productionAssertion(node == null);
fChildren.add(e);
}
// public Map/*<CAstNode,CAstEntity>*/ getScopedEntities() {
// return null; // fChildren;
// }
public Type getEnclosingType() {
return type;
}
public List<ClassMember> getInitializers() {
return fInitializers;
}
public List<ClassMember> getStaticInitializers() {
return fStaticInitializers;
}
public CAstControlFlowRecorder cfg() {
Assertions.UNREACHABLE("ClassContext.cfg()");
return null;
}
public Iterator/* <Pair<Type,Node>> */getCatchTarget(Type label) {
Assertions.UNREACHABLE("ClassContext.getCatchTarget()");
return null;
}
public Node getFinally() {
Assertions.UNREACHABLE("ClassContext.getFinally()");
return null;
}
public CodeInstance getEnclosingMethod() {
// No one outside a method defining a local class can see it,
// so it clearly can't escape through to the method's enclosing
// type...
Assertions.UNREACHABLE("ClassContext.getEnclosingMethod()");
return null;
}
public CAstSourcePositionRecorder pos() {
// No AST, so no AST map
Assertions.UNREACHABLE("ClassContext.pos()");
return null;
}
public Node getContinueFor(String label) {
Assertions.UNREACHABLE("ClassContext.getContinueFor() with label " + label + " in " + type);
return null;
}
public Node getBreakFor(String label) {
System.err.println("Cannot find break target for " + label + " in " + type);
Assertions.UNREACHABLE("ClassContext.getBreakFor()");
return null;
}
public Map<Node, String> getLabelMap() {
Assertions.UNREACHABLE("ClassContext.getLabelMap()");
return null;
}
public boolean needLVal() {
Assertions.UNREACHABLE("ClassContext.needLVal()");
return false;
}
}
public class CodeBodyContext extends DelegatingContext {
final CAstSourcePositionRecorder fSourceMap = new CAstSourcePositionRecorder();
final CAstControlFlowRecorder fCFG = new CAstControlFlowRecorder(fSourceMap);
final CAstNodeTypeMapRecorder fNodeTypeMap = new CAstNodeTypeMapRecorder();
private final Map<Node, String> labelMap = HashMapFactory.make(2);
private final Map<CAstNode, CAstEntity> fEntities;
public CodeBodyContext(WalkContext parent, Map<CAstNode, CAstEntity> entities) {
super(parent);
fEntities = entities;
}
public CAstNodeTypeMapRecorder getNodeTypeMap() {
return fNodeTypeMap;
}
public CAstSourcePositionRecorder pos() {
return fSourceMap;
}
public CAstControlFlowRecorder cfg() {
return fCFG;
}
public void addScopedEntity(CAstNode node, CAstEntity entity) {
fEntities.put(node, entity);
}
public Map/* <CAstNode,CAstEntity> */getScopedEntities() {
return fEntities;
}
public Map<Node, String> getLabelMap() {
return labelMap;
}
public boolean needLVal() {
return false;
}
}
public class MethodContext extends CodeBodyContext {
final CodeInstance fPI;
public MethodContext(CodeInstance pi, Map<CAstNode, CAstEntity> entities, WalkContext parent) {
super(parent, entities);
fPI = pi;
}
public Collection<Pair<Type, Object>> getCatchTargets(Type label) {
Collection<Pair<Type, Object>> result = Collections.singleton(Pair.<Type,Object>make(fEType, CAstControlFlowMap.EXCEPTION_TO_EXIT));
return result;
}
public CodeInstance getEnclosingMethod() {
return fPI;
}
}
private static class TryCatchContext extends DelegatingContext {
@SuppressWarnings("unused")
private final Try tryNode;
private final Context context;
Collection<Pair<Type,Object>> fCatchNodes = new ArrayList<Pair<Type, Object>>();
TryCatchContext(WalkContext parent, Try tryNode, final Context context) {
super(parent);
this.tryNode = tryNode;
this.context = context;
for (Iterator catchIter = tryNode.catchBlocks().iterator(); catchIter.hasNext();) {
Catch c = (Catch) catchIter.next();
Pair<Type,Object> p = Pair.make(c.catchType(), (Object)c);
fCatchNodes.add(p);
}
}
public Collection<Pair<Type, Object>> getCatchTargets(Type label) {
// Look for all matching targets for this thrown type:
// if supertpe match, then return only matches at this catch
// if subtype match, then matches here and parent matches
Collection<Pair<Type, Object>> catchNodes = new ArrayList<Pair<Type, Object>>();
for (Iterator<Pair<Type, Object>> iter = fCatchNodes.iterator(); iter.hasNext();) {
Pair<Type, Object> p = (Pair<Type, Object>) iter.next();
Type catchType = (Type) p.fst;
// _must_ be caught
if (label.isSubtype(catchType, this.context) || label.typeEquals(catchType, this.context)) {
catchNodes.add(p);
return catchNodes;
// _might_ get caught
} else if (catchType.isSubtype(label, this.context)) {
catchNodes.add(p);
continue;
}
}
catchNodes.addAll(getParent().getCatchTargets(label));
return catchNodes;
}
public List<ClassMember> getStaticInitializers() {
return null;
}
public List<ClassMember> getInitializers() {
return null;
}
}
protected static class RootContext implements WalkContext {
final CAstTypeDictionary fTypeDict;
public RootContext(CAstTypeDictionary typeDict) {
fTypeDict = typeDict;
}
public void addScopedEntity(CAstNode node, CAstEntity e) {
Assertions.UNREACHABLE("Attempt to call addScopedEntity() on a RootContext.");
}
public CAstControlFlowRecorder cfg() {
Assertions.UNREACHABLE("RootContext.cfg()");
return null;
}
public Collection<Pair<Type, Object>> getCatchTargets(Type label) {
Assertions.UNREACHABLE("RootContext.getCatchTargets()");
return null;
}
public CAstNodeTypeMapRecorder getNodeTypeMap() {
Assertions.UNREACHABLE("RootContext.getNodeTypeMap()");
return null;
}
public Node getFinally() {
Assertions.UNREACHABLE("RootContext.getFinally()");
return null;
}
public CAstSourcePositionRecorder pos() {
// No AST, so no AST map
Assertions.UNREACHABLE("RootContext.pos()");
return null;
}
public Node getContinueFor(String label) {
Assertions.UNREACHABLE("RootContext.getContinueFor()");
return null;
}
public Node getBreakFor(String label) {
Assertions.UNREACHABLE("RootContext.getBreakFor()");
return null;
}
public CodeInstance getEnclosingMethod() {
Assertions.UNREACHABLE("RootContext.getEnclosingMethod()");
return null;
}
public Type getEnclosingType() {
Assertions.UNREACHABLE("RootContext.getEnclosingType()");
return null;
}
public CAstTypeDictionary getTypeDictionary() {
return fTypeDict;
}
public List<ClassMember> getStaticInitializers() {
Assertions.UNREACHABLE("RootContext.getStaticInitializers()");
return null;
}
public List<ClassMember> getInitializers() {
Assertions.UNREACHABLE("RootContext.getInitializers()");
return null;
}
public Map<Node, String> getLabelMap() {
Assertions.UNREACHABLE("RootContext.getLabelMap()");
return null;
}
public boolean needLVal() {
Assertions.UNREACHABLE("ClassContext.needLVal()");
return false;
}
}
public class BreakContext extends DelegatingContext {
protected final String label;
private final Node breakTo;
BreakContext(WalkContext parent, String label, Node breakTo) {
super(parent);
this.label = label;
this.breakTo = breakTo;
}
public Node getBreakFor(String label) {
return (label == null || label.equals(this.label)) ? breakTo : super.getBreakFor(label);
}
public List<ClassMember> getStaticInitializers() {
return null;
}
public List<ClassMember> getInitializers() {
return null;
}
}
public class LoopContext extends BreakContext {
private final Node continueTo;
public LoopContext(WalkContext parent, String label, Node breakTo, Node continueTo) {
super(parent, label, breakTo);
this.continueTo = continueTo;
}
public Node getContinueFor(String label) {
return (label == null || label.equals(this.label)) ? continueTo : super.getContinueFor(label);
}
}
private class AssignmentContext extends DelegatingContext {
protected AssignmentContext(WalkContext parent) {
super(parent);
}
public boolean needLVal() {
return true;
}
}
public X10toCAstTranslator(ClassLoaderReference clr, NodeFactory nf, TypeSystem ts, X10IdentityMapper identityMapper) {
fClassLoaderRef = clr;
fTypeSystem = ts;
fNodeFactory = nf;
fIdentityMapper = identityMapper;
fNPEType = fTypeSystem.NullPointerException();
fCCEType = fTypeSystem.ClassCastException();
fEType = fTypeSystem.Exception();
fDivByZeroType = fTypeSystem.ArithmeticException();
}
public static class PolyglotSourcePosition extends AbstractSourcePosition {
private final Position p;
public PolyglotSourcePosition(Position p) {
this.p = p;
}
public int getFirstLine() {
return p.line();
}
public int getLastLine() {
return p.endLine();
}
public int getFirstCol() {
return p.column();
}
public int getLastCol() {
return p.endColumn();
}
public int getFirstOffset() {
return p.offset();
}
public int getLastOffset() {
return p.endOffset();
}
public URL getURL() {
try {
String path = p.path();
return new URL("file:" + (path.length() == 0 ? p.file() : path));
} catch (MalformedURLException e) {
Assertions.UNREACHABLE(e.toString());
return null;
}
}
public InputStream getInputStream() throws IOException {
return getURL().openConnection().getInputStream();
}
}
protected CAstSourcePositionMap.Position makePosition(Position p) {
return new PolyglotSourcePosition(p);
}
private void setPos(WalkContext wc, CAstNode cn, Node pn) {
if (pn != null) {
wc.pos().setPosition(cn, makePosition(pn.position()));
}
}
private void setPos(WalkContext wc, CAstNode cn, Position p) {
if (p != null) {
wc.pos().setPosition(cn, makePosition(p));
}
}
protected CAstNode makeNode(WalkContext wc, CAst Ast, Node n, int kind) {
CAstNode cn = Ast.makeNode(kind);
setPos(wc, cn, n);
return cn;
}
protected CAstNode makeNode(WalkContext wc, CAst Ast, Node n, int kind, CAstNode c[]) {
CAstNode cn = Ast.makeNode(kind, c);
setPos(wc, cn, n);
return cn;
}
protected CAstNode makeNode(WalkContext wc, CAst Ast, Node n, int kind, CAstNode c) {
CAstNode cn = Ast.makeNode(kind, c);
setPos(wc, cn, n);
return cn;
}
protected CAstNode makeNode(WalkContext wc, CAst Ast, Node n, int kind, CAstNode c1, CAstNode c2) {
CAstNode cn = Ast.makeNode(kind, c1, c2);
setPos(wc, cn, n);
return cn;
}
protected CAstNode makeNode(WalkContext wc, CAst Ast, Node n, int kind, CAstNode c1, CAstNode c2, CAstNode c3) {
CAstNode cn = Ast.makeNode(kind, c1, c2, c3);
setPos(wc, cn, n);
return cn;
}
protected CAstNode makeNode(WalkContext wc, CAst Ast, Node n, int kind, CAstNode c1, CAstNode c2, CAstNode c3, CAstNode c4) {
CAstNode cn = Ast.makeNode(kind, c1, c2, c3, c4);
setPos(wc, cn, n);
return cn;
}
protected CAstNode makeNode(WalkContext wc, Node n, int kind) {
return makeNode(wc, fFactory, n, kind);
}
protected CAstNode makeNode(WalkContext wc, Node n, int kind, CAstNode c[]) {
return makeNode(wc, fFactory, n, kind, c);
}
protected CAstNode makeNode(WalkContext wc, Node n, int kind, CAstNode c) {
return makeNode(wc, fFactory, n, kind, c);
}
protected CAstNode makeNode(WalkContext wc, Node n, int kind, CAstNode c1, CAstNode c2) {
return makeNode(wc, fFactory, n, kind, c1, c2);
}
protected CAstNode makeNode(WalkContext wc, Node n, int kind, CAstNode c1, CAstNode c2, CAstNode c3) {
return makeNode(wc, fFactory, n, kind, c1, c2, c3);
}
protected CAstNode makeNode(WalkContext wc, Node n, int kind, CAstNode c1, CAstNode c2, CAstNode c3, CAstNode c4) {
return makeNode(wc, fFactory, n, kind, c1, c2, c3, c4);
}
protected CAstNode makeNode(WalkContext wc, int kind, Position p) {
CAstNode cn = fFactory.makeNode(kind);
setPos(wc, cn, p);
return cn;
}
protected CAstNode makeNode(WalkContext wc, Position p, int kind, CAstNode c1) {
CAstNode cn = fFactory.makeNode(kind, c1);
setPos(wc, cn, p);
return cn;
}
protected CAstNode makeNode(WalkContext wc, Position p, int kind, CAstNode c1, CAstNode[] rest) {
CAstNode cn = fFactory.makeNode(kind, c1, rest);
setPos(wc, cn, p);
return cn;
}
protected CAstNode makeNode(WalkContext wc, Position p, int kind, CAstNode c1, CAstNode c2) {
CAstNode cn = fFactory.makeNode(kind, c1, c2);
setPos(wc, cn, p);
return cn;
}
protected CAstNode makeNode(WalkContext wc, Position p, int kind, CAstNode c1, CAstNode c2, CAstNode c3) {
CAstNode cn = fFactory.makeNode(kind, c1, c2, c3);
setPos(wc, cn, p);
return cn;
}
protected CAstNode makeNode(WalkContext wc, Position p, int kind, CAstNode c1, CAstNode c2, CAstNode c3, CAstNode c4) {
CAstNode cn = fFactory.makeNode(kind, c1, c2, c3, c4);
setPos(wc, cn, p);
return cn;
}
public CAstEntity translate(Object ast, String fileName) {
return walkEntity((Node) ast, new RootContext(getTypeDict()));
}
protected static Collection<CAstQualifier> mapFlagsToQualifiers(Flags flags) {
Set<CAstQualifier> quals = new LinkedHashSet<CAstQualifier>();
if (flags.isAbstract())
quals.add(CAstQualifier.ABSTRACT);
if (flags.isFinal())
quals.add(CAstQualifier.FINAL);
if (flags.isInterface())
quals.add(CAstQualifier.INTERFACE);
if (flags.isNative())
quals.add(CAstQualifier.NATIVE);
// if (flags.isPackage()) quals.add(CAstQualifier.PACKAGE);
if (flags.isPrivate())
quals.add(CAstQualifier.PRIVATE);
if (flags.isProtected())
quals.add(CAstQualifier.PROTECTED);
if (flags.isPublic())
quals.add(CAstQualifier.PUBLIC);
if (flags.isStatic())
quals.add(CAstQualifier.STATIC);
if (flags.isTransient())
quals.add(CAstQualifier.TRANSIENT);
return quals;
}
protected void processClassMembers(Node n, ClassType classType, List<ClassMember> members, DelegatingContext classContext,
List<CAstEntity> memberEntities) {
// Collect all initializer-related gorp
for (Iterator memberIter = members.iterator(); memberIter.hasNext();) {
ClassMember member = (ClassMember) memberIter.next();
if (member instanceof Initializer) {
Initializer initializer = (Initializer) member;
if (initializer.flags().flags().isStatic())
classContext.getStaticInitializers().add(initializer);
else
classContext.getInitializers().add(initializer);
} else if (member instanceof FieldDecl) {
FieldDecl fd = (FieldDecl) member;
if (fd.init() != null) {
if (fd.flags().flags().isStatic())
classContext.getStaticInitializers().add(fd);
else
classContext.getInitializers().add(fd);
}
}
}
// Now process
for (Iterator memberIter = members.iterator(); memberIter.hasNext();) {
ClassMember member = (ClassMember) memberIter.next();
if (!(member instanceof Initializer)) {
CAstEntity memberEntity = walkEntity(member, classContext);
memberEntities.add(memberEntity);
}
}
// add class initializer, if needed
if (!classContext.getStaticInitializers().isEmpty()) {
InitializerDef initDef = fTypeSystem.initializerDef(n.position(), Types.ref(classType), Flags.STATIC);
InitializerInstance initInstance = fTypeSystem.createInitializerInstance(n.position(), Types.ref(initDef));
Map<CAstNode, CAstEntity> childEntities = HashMapFactory.make();
final MethodContext mc = new MethodContext(initInstance, childEntities, classContext);
List inits = classContext.getStaticInitializers();
CAstNode[] bodyNodes = new CAstNode[inits.size()];
insertInitializers(mc, bodyNodes, true, 0);
CAstNode ast = makeNode(mc, fFactory, n, CAstNode.BLOCK_STMT, bodyNodes);
memberEntities.add(new ProcedureEntity(ast, fTypeSystem, initInstance, new String[0], childEntities, mc));
}
}
protected void addConstructorsToAnonymousClass(New n, ClassType anonType, ClassContext classContext,
List<CAstEntity> memberEntities) {
List superConstructors = ((ClassType) anonType.superClass()).constructors();
for (Iterator iter = superConstructors.iterator(); iter.hasNext();) {
ConstructorInstance superCtor = (ConstructorInstance) iter.next();
Map<CAstNode, CAstEntity> childEntities = HashMapFactory.make();
final MethodContext mc = new MethodContext(superCtor, childEntities, classContext);
String[] fakeArguments = new String[superCtor.formalTypes().size() + 1];
for (int i = 0; i < fakeArguments.length; i++) {
fakeArguments[i] = (i == 0) ? "this" : ("argument" + i);
}
List inits = classContext.getInitializers();
CAstNode[] bodyNodes = new CAstNode[inits.size() + 1];
CallSiteReference callSiteRef = CallSiteReference.make(0, fIdentityMapper.getMethodRef(superCtor),
IInvokeInstruction.Dispatch.SPECIAL);
CAstNode[] children = new CAstNode[fakeArguments.length + 1];
children[0] = makeNode(mc, fFactory, n, CAstNode.SUPER);
children[1] = fFactory.makeConstant(callSiteRef);
for (int i = 1; i < fakeArguments.length; i++) {
children[i + 1] = makeNode(mc, fFactory, n, CAstNode.VAR, fFactory.makeConstant(fakeArguments[i]));
}
bodyNodes[0] = makeNode(mc, fFactory, n, CAstNode.CALL, children);
insertInitializers(mc, bodyNodes, false, 1);
CAstNode ast = makeNode(mc, fFactory, n, CAstNode.BLOCK_STMT, bodyNodes);
memberEntities.add(new ProcedureEntity(ast, fTypeSystem, superCtor, anonType, fakeArguments, childEntities, mc));
}
}
public static String anonTypeName(ClassType ct) {
Position pos = ct.position();
return ct.fullName() + "$" + pos.line() + "$" + pos.column();
}
@SuppressWarnings("unchecked")
protected CAstEntity SUPER_walkEntity(Node rootNode, final WalkContext context) {
if (rootNode instanceof SourceFile) {
SourceFile file = (SourceFile) rootNode;
List<CAstEntity> declEntities = new ArrayList<CAstEntity>();
for (Iterator iter = file.decls().iterator(); iter.hasNext();) {
TopLevelDecl decl = (TopLevelDecl) iter.next();
declEntities.add(walkEntity(decl, context));
}
return new CompilationUnitEntity(file, declEntities);
} else if (rootNode instanceof ClassDecl) {
final ClassDecl cd = (ClassDecl) rootNode;
final List<CAstEntity> memberEntities = new ArrayList<CAstEntity>();
final ClassContext classContext = new ClassContext(cd.classDef().asType(), memberEntities, context);
processClassMembers(rootNode, cd.classDef().asType(), cd.body().members(), classContext, memberEntities);
return new ClassEntity(classContext, memberEntities, cd, cd.position());
} else if (rootNode instanceof New) {
final New n = (New) rootNode;
final List<CAstEntity> memberEntities = new ArrayList<CAstEntity>();
ClassType anonType = (ClassType) n.anonType().asType();
String anonTypeName = anonTypeName(anonType);
final ClassContext classContext = new ClassContext(anonType, memberEntities, context);
processClassMembers(rootNode, anonType, n.body().members(), classContext, memberEntities);
addConstructorsToAnonymousClass(n, anonType, classContext, memberEntities);
return new ClassEntity(classContext, memberEntities, anonType, anonTypeName, n.position());
} else if (rootNode instanceof ProcedureDecl) {
final ProcedureDecl pd = (ProcedureDecl) rootNode;
final Map<CAstNode, CAstEntity> memberEntities = new LinkedHashMap<CAstNode, CAstEntity>();
final MethodContext mc = new MethodContext(pd.procedureInstance().asInstance(), memberEntities, context);
CAstNode pdAST = null;
if (!pd.flags().flags().isAbstract()) {
// Presumably the MethodContext's parent is a ClassContext,
// and he has the list of initializers. Hopefully the following
// will glue that stuff in the right place in any constructor body.
pdAST = walkNodes(pd, mc);
}
List/* <Formal> */formals = pd.formals();
String[] argNames;
int i = 0;
if (!pd.flags().flags().isStatic()) {
argNames = new String[formals.size() + 1];
argNames[i++] = "this";
} else {
argNames = new String[formals.size()];
}
for (Iterator iter = formals.iterator(); iter.hasNext(); i++) {
Formal formal = (Formal) iter.next();
argNames[i] = formal.name().toString();
}
return new ProcedureEntity(pdAST, fTypeSystem, pd.procedureInstance().asInstance(), argNames, memberEntities, mc);
} else if (rootNode instanceof FieldDecl) {
final FieldDecl fd = (FieldDecl) rootNode;
return new FieldEntity(fd, context);
} else {
Assertions.UNREACHABLE("Unknown node type for walkEntity():" + rootNode.getClass().getName());
return null;
}
}
private boolean isSpecialCallStmt(Stmt maybeSuper, Kind kind) {
if (maybeSuper instanceof ConstructorCall) {
ConstructorCall cc = (ConstructorCall) maybeSuper;
return cc.kind() == kind;
}
return false;
}
private boolean hasSpecialCall(Block body, Kind kind) {
if (body.statements().size() <= 0)
return false;
Stmt maybeSuper = (Stmt) body.statements().get(0);
return isSpecialCallStmt(maybeSuper, kind);
}
private boolean hasSuperCall(Block body) {
return hasSpecialCall(body, ConstructorCall.SUPER);
}
private boolean hasThisCall(Block body) {
return hasSpecialCall(body, ConstructorCall.THIS);
}
private int insertInitializers(WalkContext wc, CAstNode[] initCode, boolean wantStatic, int offset) {
List inits = wantStatic ? wc.getStaticInitializers() : wc.getInitializers();
for (Iterator iter = inits.iterator(); iter.hasNext(); offset++) {
ClassMember init = (ClassMember) iter.next();
CAstNode initNode = walkNodes(init, wc);
if (initNode != null) {
initCode[offset] = initNode;
} else {
initCode[offset] = makeNode(wc, fFactory, null, CAstNode.EMPTY);
}
}
return offset;
}
public interface ParametricType extends CAstType.Class {
List<CAstType> getParameters();
}
public class PolyglotJavaParametricType extends PolyglotJavaType implements ParametricType {
private final List<Type> fPolyglotTypeParameters;
private List<CAstType> fTypeParameters = null;
public PolyglotJavaParametricType(ClassType baseType, List<Type> typeParams, CAstTypeDictionary dict, TypeSystem system) {
super(baseType, dict, system);
fPolyglotTypeParameters= typeParams;
}
public List<CAstType> getParameters() {
if (fTypeParameters == null) {
buildTypeParameters();
}
return fTypeParameters;
}
private void buildTypeParameters() {
for(Type typeParam: fPolyglotTypeParameters) {
fTypeParameters.add(fDict.getCAstTypeFor(typeParam));
}
}
@Override
public String toString() {
StringBuilder sb= new StringBuilder();
sb.append(fType.fullName());
sb.append("<");
int idx= 0;
for(Type typeParam: fPolyglotTypeParameters) {
if (idx++ > 0) { sb.append(", "); }
sb.append(typeParam.toString());
}
sb.append(">");
return sb.toString();
}
}
protected X10TranslatorVisitor createTranslator() {
return new X10TranslatingVisitorImpl();
}
protected CAstEntity walkAsyncEntity(final Node rootNode, final Node bodyNode, final WalkContext context) {
Map<CAstNode,CAstEntity> childEntities= new HashMap<CAstNode,CAstEntity>();
final CodeBodyContext asyncContext= new CodeBodyContext(context, childEntities);
final CAstNode bodyAST= walkNodes(bodyNode, asyncContext);
return new AsyncEntity(childEntities, rootNode, asyncContext, bodyAST);
}
protected CAstEntity walkClosureEntity(final Closure rootNode, final Node bodyNode, final WalkContext context) {
Map<CAstNode,CAstEntity> childEntities = new HashMap<CAstNode,CAstEntity>();
final MethodContext closureContext = new MethodContext(rootNode.closureDef().asInstance(), childEntities, context);
final CAstNode bodyAST = walkNodes(bodyNode, closureContext);
final List<Formal> formals = rootNode.formals();
final Collection<String> argNames = new ArrayList<String>();
final Collection<CAstNode> bodyNodes = new ArrayList<CAstNode>();
// closure object is the receiver
argNames.add("$this");
for (final Formal formal : formals) {
argNames.add(formal.name().toString());
if (formal instanceof X10Formal) {
final X10Formal x10Formal = (X10Formal) formal;
if (x10Formal.hasExplodedVars()) {
int i = 0;
for (final Formal explodedVarFormal : x10Formal.vars()) {
bodyNodes.add(createExplodedVarInitialization(context, formal, explodedVarFormal, i++));
}
}
}
}
final CAstNode newBodyAst;
if (bodyNodes.isEmpty()) {
newBodyAst = bodyAST;
} else {
// We want to access directly to the block statement.
bodyNodes.add(bodyAST.getChild(0).getChild(0));
newBodyAst = makeNode(context, fFactory, bodyNode, CAstNode.LOCAL_SCOPE,
makeNode(context, fFactory, bodyNode, CAstNode.BLOCK_STMT,
bodyNodes.toArray(new CAstNode[bodyNodes.size()])));
}
return new ClosureBodyEntity(childEntities, rootNode, closureContext, newBodyAst, context.getEnclosingType(),
argNames.toArray(new String[argNames.size()]),
bodyNodes.toArray(new CAstNode[bodyNodes.size()]));
}
private CAstNode createExplodedVarInitialization(final WalkContext context, final Formal parameter,
final Formal explodedVar, final int index) {
final CAstNode recvNode = makeNode(context, parameter.position(), CAstNode.VAR,
fFactory.makeConstant(parameter.name().toString()));
final TypeReference typeRef = fIdentityMapper.getTypeRef(parameter.type().type());
final MethodReference methodRef = MethodReference.findOrCreate(typeRef, Atom.findOrCreateAsciiAtom("apply"),
Descriptor.findOrCreateUTF8("(I)Lx10/lang/Int;"));
final CallSiteReference csRef = CallSiteReference.make(0, methodRef, IInvokeInstruction.Dispatch.VIRTUAL);
return makeNode(context, parameter.position(), CAstNode.DECL_STMT,
fFactory.makeConstant(new CAstSymbolImpl(explodedVar.name().toString(), false)),
makeNode(context, fFactory, parameter, CAstNode.CALL,
new CAstNode[] { recvNode, fFactory.makeConstant(csRef),
fFactory.makeConstant(index)}));
}
private final class AsyncBodyType implements CAstType.Method {
private final Node fNode;
private final Type declaringType;
private AsyncBodyType(Node node, Type declaringType) {
super();
fNode= node;
this.declaringType = declaringType;
}
public CAstType getReturnType() {
return getTypeDict().getCAstTypeFor(
/*(fNode instanceof Future) ?
((Future) fNode).type() :*/
fTypeSystem.Void());
}
public List getArgumentTypes() {
return Collections.EMPTY_LIST;
}
public Collection getExceptionTypes() {
// TODO should figure out what exceptions can really be thrown by the body
return Collections.EMPTY_LIST;
}
public int getArgumentCount() {
return 0;
}
public String getName() {
return "<activity>";
}
public Collection getSupertypes() {
// [DC] don't know why an async body had type Object, assuming it's a placeholder
// so Any seems like a reasonable replacement
return Collections.singleton(getTypeDict().getCAstTypeFor(fTypeSystem.Any()));
}
public CAstType getDeclaringType() {
return getTypeDict().getCAstTypeFor(declaringType);
}
}
final class AsyncEntity extends CodeBodyEntity {
private final CodeBodyContext fContext;
private final CAstNode fBodyast;
private final CAstSourcePositionMap.Position fPosition;
private final AsyncBodyType fBodyType;
private AsyncEntity(Map<CAstNode,CAstEntity> entities, Node node, CodeBodyContext context, CAstNode bodyast) {
super(entities);
fPosition= makePosition(node.position());
fContext= context;
fBodyast= bodyast;
fBodyType= new AsyncBodyType(node, fContext.getEnclosingType());
}
public CAstSourcePositionMap.Position getPosition() {
return fPosition;
}
public int getKind() {
return X10CAstEntity.ASYNC_BODY;
}
public String getName() {
return "<activity " + fPosition.getURL() + ":" + fPosition.getFirstLine() + ":" + fPosition.getFirstCol() + ">";
}
public String[] getArgumentNames() {
return new String[0];
}
public CAstNode[] getArgumentDefaults() {
return new CAstNode[0];
}
public int getArgumentCount() {
return 0;
}
public CAstNode getAST() {
return fBodyast;
}
public CAstControlFlowMap getControlFlow() {
return fContext.cfg();
}
public CAstSourcePositionMap getSourceMap() {
return fContext.pos();
}
public CAstNodeTypeMap getNodeTypeMap() {
return fContext.getNodeTypeMap();
}
public Collection getQualifiers() {
return Collections.EMPTY_LIST;
}
public CAstType getType() {
return fBodyType;
}
public String toString() {
return getName();
}
}
class X10TranslatingVisitorImpl extends JavaTranslatingVisitorImpl implements X10TranslatorVisitor {
@Override
public CAstNode visit(ConstructorDecl cd, WalkContext mc) {
if (cd.body() == null) { // PORT1.7 Body can be null
return makeNode(mc, fFactory, cd, CAstNode.BLOCK_STMT, new CAstNode[0]);
}
return super.visit(cd, mc);
}
private MethodInstance findMethod(Type container, Name name, Type arg1, Type arg2) {
List<Type> argTypes = new ArrayList<Type>();
argTypes.add(arg1);
argTypes.add(arg2);
try {
return fTypeSystem.findMethod(container, fTypeSystem.MethodMatcher(container, name, argTypes, fTypeSystem.emptyContext()));
} catch (SemanticException e) {
return null;
}
}
// FIXME: workaround for XTENLANG-2278. Remove when the WALA bridge is updated.
@Override
public CAstNode visit(Binary b, WalkContext context) {
Binary.Operator op = b.operator();
Expr left = b.left();
Expr right = b.right();
Position pos = b.position();
Type Region = fTypeSystem.Region();
if (op == Binary.Operator.DOT_DOT) {
Assertions.productionAssertion(left.type().isInt() && right.type().isInt(), "Operator .. on ("+left.type()+","+right.type()+")");
Name makeRectangular = Name.make("makeRectangular");
Call mr = fNodeFactory.Call(pos, fNodeFactory.CanonicalTypeNode(pos, Region),
fNodeFactory.Id(pos, makeRectangular), left, right);
Type Int = fTypeSystem.Int();
MethodInstance mi = findMethod(Region, makeRectangular, Int, Int);
mr = mr.methodInstance(mi);
mr = (Call) mr.type(mi.returnType());
return visit(mr, context);
} else if (op == Binary.Operator.ARROW) {
Assertions.productionAssertion(fTypeSystem.isRegion(left.type()) && fTypeSystem.isPlace(right.type()), "Operator -> on ("+left.type()+","+right.type()+")");
Type Dist = fTypeSystem.Dist();
Name makeConstant = Name.make("makeConstant");
Call mc = fNodeFactory.Call(pos, fNodeFactory.CanonicalTypeNode(pos, Dist),
fNodeFactory.Id(pos, makeConstant), left, right);
Type Place = fTypeSystem.Place();
MethodInstance mi = findMethod(Dist, makeConstant, Region, Place);
mc = mc.methodInstance(mi);
mc = (Call) mc.type(mi.returnType());
return visit(mc, context);
}
return super.visit(b, context);
}
public CAstNode visit(Async a, WalkContext context) {
CAstEntity bodyEntity= walkAsyncEntity(a, a.body(), context);
List clocks = a.clocks();
CAstNode args[] = new CAstNode[ clocks.size()+1 ];
// args[0] = walkNodes(a.place(), context);
for(int i = 0; i < clocks.size(); i++) {
args[i] = walkNodes((Node)clocks.get(i), context);
}
// FUNCTION_EXPR will translate to a type wrapping the single method with the given body
args[args.length-1] = makeNode(context, a.body(), CAstNode.FUNCTION_EXPR, fFactory.makeConstant(bodyEntity));
CAstNode asyncNode= makeNode(context, a, X10CastNode.ASYNC, args);
context.addScopedEntity(asyncNode, bodyEntity);
return asyncNode;
}
public CAstNode visit(Finish f, WalkContext context) {
return makeNode(context, f, CAstNode.UNWIND,
makeNode(context, f, CAstNode.BLOCK_STMT,
makeNode(context, X10CastNode.FINISH_ENTER, f.body().position().startOf()),
walkNodes(f.body(), context)),
makeNode(context, X10CastNode.FINISH_EXIT, f.body().position().endOf()));
}
private CAstNode walkIterator(X10Loop loop, final CAstNode bodyNode, WalkContext context) {
return walkIterator(loop.formal(), bodyNode, walkNodes(loop.domain(), context), loop.position(), context);
}
private CAstNode walkIterator(Formal formal, final CAstNode bodyNode, CAstNode domainNode, polyglot.util.Position bodyPos, WalkContext wc) {
X10Formal x10Formal= (X10Formal) formal;
LocalDef[] vars = x10Formal.localInstances();
CAstNode[] bodyStmts = new CAstNode[vars.length + 1]; // var decls + bodyNode
for (int i = 0; i < vars.length; i++)
bodyStmts[i]= makeNode(wc, vars[i].position(), CAstNode.DECL_STMT,
fFactory.makeConstant(new CAstSymbolImpl(vars[i].name().toString(), vars[i].flags().isFinal())),
makeNode(wc, vars[i].position(), CAstNode.ARRAY_REF,
makeNode(wc, vars[i].position(), CAstNode.VAR, fFactory.makeConstant(formal.name().id().toString())),
fFactory.makeConstant(TypeReference.Int),
fFactory.makeConstant(i)));
bodyStmts[vars.length] = bodyNode;
return makeNode(wc, bodyPos, CAstNode.LOCAL_SCOPE,
makeNode(wc, bodyPos, CAstNode.BLOCK_STMT,
makeNode(wc, formal, CAstNode.DECL_STMT, fFactory.makeConstant(new CAstSymbolImpl("iter tmp", false)),
makeNode(wc, formal, X10CastNode.ITER_INIT, domainNode)),
makeNode(wc, bodyPos, CAstNode.LOOP,
makeNode(wc, formal, X10CastNode.ITER_HASNEXT,
makeNode(wc, formal, CAstNode.VAR, fFactory.makeConstant("iter tmp"))),
makeNode(wc, bodyPos, CAstNode.BLOCK_STMT,
makeNode(wc, formal, CAstNode.DECL_STMT, walkNodes(formal, wc),
makeNode(wc, formal, X10CastNode.ITER_NEXT, makeNode(wc, formal, CAstNode.VAR, fFactory.makeConstant("iter tmp")))),
bodyStmts))));
}
/*
public CAstNode visit(Future f, WalkContext wc) {
CAstEntity bodyEntity= walkAsyncEntity(f, f.body(), wc);
CAstNode bodyNode= makeNode(wc, f, X10CastNode.ASYNC,
walkNodes(f.place(), wc),
// FUNCTION_EXPR will translate to a type wrapping the single method with the given body
makeNode(wc, f.body(), CAstNode.FUNCTION_EXPR, fFactory.makeConstant(bodyEntity)));
wc.addScopedEntity(bodyNode, bodyEntity);
return bodyNode;
}
*/
public CAstNode visit(Tuple t, WalkContext wc) {
CAstNode[] children = new CAstNode[t.arguments().size()+1];
// N.B.: The type of the result will be Rail[T], where T is the LUB of all the child expr types.
TypeReference tupleTypeRef = fIdentityMapper.getTypeRef(t.type());
int idx= 0;
children[idx++] = fFactory.makeConstant(tupleTypeRef);
for(Expr child: t.arguments()) {
children[idx++] = walkNodes(child, wc);
}
return makeNode(wc, fFactory, t, X10CastNode.TUPLE, children);
}
public CAstNode visit(SettableAssign n, WalkContext wc) {
Expr array = n.array();
List<Expr> indices = n.index();
Assign.Operator op = n.operator();
Expr rhs = n.right();
CAstNode lhsCAstNode = visitArrayAccess(n, array, indices, wc);
return processAssign(n, lhsCAstNode, op, rhs, wc);
}
public CAstNode visitArrayAccess(Expr access, Expr array, List<Expr> indices, WalkContext wc) {
TypeReference eltTypeRef = fIdentityMapper.getTypeRef(array.type());
CAstNode[] children= new CAstNode[indices.size()+2];
hookUpNPETargets(access, wc); // as for base class visit(ArrayAccess), right???
int idx= 0;
children[idx++]= walkNodes(array, wc);
children[idx++]= fFactory.makeConstant(eltTypeRef);
for(Expr index: indices) {
children[idx++]= walkNodes(index, wc);
}
return makeNode(wc, fFactory, access, isIndexedByPoint(indices) ? X10CastNode.ARRAY_REF_BY_POINT : CAstNode.ARRAY_REF, children);
}
public CAstNode visitArrayAccess1D(Expr access, Expr array, Expr index, WalkContext wc) {
TypeReference eltTypeRef = fIdentityMapper.getTypeRef(array.type());
CAstNode[] children= new CAstNode[3];
int idx= 0;
children[idx++]= walkNodes(array, wc);
children[idx++]= fFactory.makeConstant(eltTypeRef);
children[idx++]= walkNodes(index, wc);
return makeNode(wc, fFactory, array, isIndexedByPoint(index) ? X10CastNode.ARRAY_REF_BY_POINT : CAstNode.ARRAY_REF, children);
}
private boolean isIndexedByPoint(Expr index) {
return index.type().isSubtype(((TypeSystem) fTypeSystem).Point(), fTypeSystem.emptyContext());
}
private CAstNode visitArrayAssign(Expr assign, Expr array, List<Expr> indices, WalkContext wc) {
throw new UnsupportedOperationException();
}
public CAstNode visit(AssignPropertyCall a, WalkContext wc) {
// TODO process the assignments
return makeNode(wc, fFactory, null, CAstNode.EMPTY);
}
public CAstNode visit(Call c, WalkContext wc) {
x10.types.MethodInstance methodInstance= c.methodInstance();
ContainerType methodOwner= methodInstance.container();
/*
//PORT1.7 Array accesses are now represented as ordinary method calls
if (methodOwner instanceof ClassType) {
ClassType classType = (ClassType) methodOwner;
String className = classType.fullName().toString();
final QName settableName = QName.make("x10.lang.Settable");
boolean isSettable = false;
for (final Type type : classType.interfaces()) {
if (type instanceof Named) {
if (((Named) type).fullName().equals(settableName)) {
isSettable = true;
break;
}
}
}
if (className.equals("x10.lang.Array") || isSettable) {
if (c.name().id().toString().equals("apply")) {
Expr array = (Expr) c.target();
List<Expr> indices = c.arguments();
return visitArrayAccess(c, array, indices, wc);
} else if (c.name().id().toString().equals("set")) {
Expr array = (Expr) c.target();
List<Expr> indices = c.arguments();
return visitArrayAssign(c, array, indices, wc);
}
}
} else if (methodOwner instanceof ParametrizedType) {
ParametrizedType parType = (ParametrizedType) methodOwner;
String baseName = parType.fullName().toString();
if (baseName.equals("x10.lang.Future")) {
List<Type> typeParms= parType.typeParameters();
Type retType= typeParms.get(0);
TypeReference typeRef= TypeReference.findOrCreate(fClassLoaderRef, fIdentityMapper.typeToTypeID(retType));
return makeNode(wc, c, X10CastNode.FORCE, walkNodes(c.target(), wc), fFactory.makeConstant(typeRef));
}
}
*/
return super.visit(c, wc);
}
public CAstNode visit(Here h, WalkContext context) {
return makeNode(context, h, X10CastNode.HERE);
}
public CAstNode visit(LocalTypeDef l, WalkContext context) {
return fFactory.makeNode(CAstNode.EMPTY);
}
public CAstNode visit(Next n, WalkContext context) {
return makeNode(context, n, X10CastNode.NEXT);
}
public CAstNode visit(When w, WalkContext wc) {
When_c when= (When_c) w;
// List/*<When.Branch>*/ branches= when.branches();
List/*<Expr>*/ exprs= when.exprs();
List/*<Stmt>*/ stmts= when.stmts();
// In the fullness of time, some analyses may want to have "when" constructs
// clearly marked in a more declarative fashion, but for now, this has the
// advantage of making the operational semantics clear, with minimal extra
// machinery.
Assertions.productionAssertion(exprs.size() == stmts.size());
CAstNode[] whenClauses= new CAstNode[exprs.size()+1];
CAstNode whenExit= makeNode(wc, w.position().endOf(), CAstNode.LABEL_STMT,
fFactory.makeConstant("when exit"),
makeNode(wc, CAstNode.EMPTY, w.position().endOf()));
wc.cfg().map(whenExit, whenExit);
int idx= 0;
Iterator stmtIter= IteratorPlusOne.make(stmts.iterator(), when.stmt());
for(Iterator exprIter= IteratorPlusOne.make(exprs.iterator(), when.expr()); exprIter.hasNext(); idx++) {
// Branch b= (Branch) iter.next();
Expr expr= (Expr) exprIter.next();
Stmt stmt= (Stmt) stmtIter.next();
CAstNode whenBreak= makeNode(wc, expr, CAstNode.GOTO);
whenClauses[idx]= makeNode(wc, expr, CAstNode.IF_STMT,
walkNodes(expr, wc),
makeNode(wc, stmt, CAstNode.BLOCK_STMT,
walkNodes(stmt, wc),
whenBreak));
wc.cfg().map(whenBreak, whenBreak);
wc.cfg().add(whenBreak, whenExit, null);
}
return makeNode(wc, w, CAstNode.BLOCK_STMT,
makeNode(wc, w, CAstNode.LOOP,
fFactory.makeConstant(true),
wrapBodyInAtomic(makeNode(wc, w, CAstNode.BLOCK_STMT, whenClauses), w, wc)),
whenExit);
// Alternative, quasi-declarative representation:
// CAstNode[] branchNodes= new CAstNode[branches.size()*2];
//
// int idx= 0;
// for(Iterator iter= branches.iterator(); iter.hasNext(); idx += 2) {
// Branch b= (Branch) iter.next();
//
// branchNodes[idx]= walkNodes(b.expr(), context);
// branchNodes[idx+1]= walkNodes(b.stmt(), context);
// }
// return fFactory.makeNode(X10CastNode.WHEN, branchNodes);
}
public CAstNode visit(X10Formal f, WalkContext context) {
return fFactory.makeConstant(new CAstSymbolImpl(f.name().id().toString(), true));
}
public CAstNode visit(Clocked c, WalkContext context) {
Assertions.UNREACHABLE();
return null;
}
public CAstNode visit(Atomic a, WalkContext context) {
final CAstNode bodyNode= walkNodes(a.body(), context);
return wrapBodyInAtomic(bodyNode, a, context);
}
private CAstNode wrapBodyInAtomic(final CAstNode bodyNode, Node n, WalkContext wc) {
return makeNode(wc, n, CAstNode.UNWIND,
makeNode(wc, n, CAstNode.BLOCK_STMT,
makeNode(wc, X10CastNode.ATOMIC_ENTER, n.position().startOf()),
bodyNode),
makeNode(wc, X10CastNode.ATOMIC_EXIT, n.position().startOf()));
}
private boolean isIndexedByPoint(List<Expr> indices) {
if (indices.size() > 1) return false;
return isIndexedByPoint(indices.get(0));
}
// private int tempCtr= 0;
//
// public CAstNode visit(ArrayConstructor ac, WalkContext wc) {
// Expr dist= ac.distribution();
// Expr init= ac.initializer();
// Type arrayType= ac.type();
// // TODO Filter arrayType so that e.g. x10.lang.IntReferenceArray becomes int[] so
// // that WALA doesn't complain that an array type doesn't seem to be an array type.
// /* if (arrayType instanceof X10ParsedClassType_c) {
// X10ParsedClassType_c t = ((X10ParsedClassType_c)arrayType);
// List<Type> ps = t.typeParameters();
// if (ps.size() == 1) {
// arrayType = ps.get(0).arrayOf();
// }
// }
// // ugly hackish attempt to find array type. unlikely to be right all the time
// */
// TypeReference arrayTypeRef= fIdentityMapper.getTypeRef(arrayType);
// Type baseType= ac.arrayBaseType().type();
// TypeReference baseTypeRef= fIdentityMapper.getTypeRef(baseType);
//
// if (init instanceof Closure) {
// Closure closure= (Closure) init;
// Formal formal1= (Formal) closure.formals().get(0); // The closure for an array ctor init always has a single argument
// // Turn this construct into an array allocation followed by a region
// // iteration whose body calls the initializer and assigns the result
// // to the corresponding array slot.
// //
// // BLOCK_EXPR [
// // ASSIGN [ arrayTmp, NEW [ type, dist.region ] ],
// // for(point p: dist.region) {
// // ASSIGN [ ARRAY_REF [ arrayTmp, p ], CALL [ closure, p ] ]
// // }
// // tmp
// // ]
// //
// CAstNode closureNode= walkNodes(closure, wc);
// String arrayTempName= "array temp" + tempCtr;
// String distTempName= "dist temp" + tempCtr++;
// CAstSymbol arrayTemp= new AstTranslator.InternalCAstSymbol(arrayTempName, true);
// CAstSymbol distTemp= new AstTranslator.InternalCAstSymbol(distTempName, true);
// CAstNode distDeclNode=
// makeNode(wc, dist, CAstNode.DECL_STMT,
// fFactory.makeConstant(distTemp),
// walkNodes(dist, wc));
// CAstNode arrayNewNode=
// makeNode(wc, ac, CAstNode.DECL_STMT,
// fFactory.makeConstant(arrayTemp),
// makeNode(wc, ac, CAstNode.NEW,
// fFactory.makeConstant(arrayTypeRef),
// makeNode(wc, fFactory, dist, CAstNode.VAR, fFactory.makeConstant(distTempName))));
// int dummyPC = 0; // Just wrap the kind of call; the "rear end" won't care about anything else...
// MethodReference closureRef= createMethodRefForClosure(closure);
// CallSiteReference closureCallSiteRef= CallSiteReference.make(dummyPC, closureRef, IInvokeInstruction.Dispatch.VIRTUAL);
// CAstNode arrayElemInit= makeNode(wc, closure, CAstNode.BLOCK_EXPR,
// makeNode(wc, formal1, CAstNode.ASSIGN,
// makeNode(wc, closure, X10CastNode.ARRAY_REF_BY_POINT,
// makeNode(wc, closure, CAstNode.VAR, fFactory.makeConstant(arrayTempName)),
// fFactory.makeConstant(baseTypeRef),
// makeNode(wc, fFactory, formal1, CAstNode.VAR, fFactory.makeConstant(formal1.name()))),
// makeNode(wc, closure, CAstNode.CALL,
// closureNode,
// fFactory.makeConstant(closureCallSiteRef),
// makeNode(wc, fFactory, formal1, CAstNode.VAR, fFactory.makeConstant(formal1.name())))));
//
// CAstNode loopBody=
// walkIterator(formal1, arrayElemInit,
// makeNode(wc, dist, CAstNode.VAR, fFactory.makeConstant(distTempName)), closure.position(), wc);
//
// return makeNode(wc, closure, CAstNode.BLOCK_EXPR, // NEED CAstNode.LOCAL_SCOPE or make "array temp" names unique
// distDeclNode,
// arrayNewNode,
// loopBody,
// makeNode(wc, fFactory, formal1, CAstNode.VAR, fFactory.makeConstant(arrayTempName)));
// } else if (init instanceof ArrayInit) {
// ArrayInit arrayInit= (ArrayInit) init;
// // ARRAY_NEW [ type, dist.region, walkNodes(init, wc) ]
// CAstNode[] eltNodes= new CAstNode[arrayInit.elements().size()+1];
// int idx= 0;
// eltNodes[idx++]= makeNode(wc, ac, CAstNode.NEW,
// fFactory.makeConstant(arrayTypeRef),
// walkNodes(dist, wc));
// for(Iterator iter= arrayInit.elements().iterator(); iter.hasNext(); ) {
// Expr elem= (Expr) iter.next();
// eltNodes[idx++]= walkNodes(elem, wc);
// }
// return makeNode(wc, init, CAstNode.ARRAY_LITERAL, eltNodes);
// } else if (init == null) {
// return makeNode(wc, ac, CAstNode.NEW,
// fFactory.makeConstant(arrayTypeRef),
// walkNodes(dist, wc));
// } else {
// Assertions.UNREACHABLE("ArrayConstructor has non-closure, non-ArrayInit initializer of type " + init.getClass());
// return null;
// }
// }
//
private String castNameForType(Type type) {
return getTypeDict().getCAstTypeFor(type).getName();
}
/*
private MethodReference createMethodRefForClosure(Closure closure) {
List formals= closure.formals();
TypeName[] argTypes= new TypeName[formals.size()];
for(int i= 0; i < argTypes.length; i++) {
Formal f= (Formal) formals.get(i);
argTypes[i]= TypeName.findOrCreate(castNameForType(f.type().type()));
}
TypeName retType= TypeName.findOrCreate(castNameForType(closure.returnType().type()));
MethodReference closureRef= MethodReference.findOrCreate(
TypeReference.findOrCreate(fClassLoaderRef, "Lclosure" + new PolyglotSourcePosition(closure.position())),
new Selector(Atom.findOrCreateAsciiAtom("invoke"), Descriptor.findOrCreate(argTypes, retType)));
return closureRef;
}
*/
/*
public CAstNode visit(GenParameterExpr gpe, WalkContext context) {
// TODO Auto-generated method stub
return null;
}
*/
public CAstNode visit(ForLoop f, WalkContext context) {
Node breakTarget = makeBreakTarget(f);
Node continueTarget = makeContinueTarget(f);
String loopLabel = (String) context.getLabelMap().get(f);
WalkContext lc = new LoopContext(context, loopLabel, breakTarget, continueTarget);
return makeNode(context, f, CAstNode.BLOCK_STMT,
walkNodes(breakTarget, context),
walkIterator(f,
makeNode(context, f, CAstNode.BLOCK_STMT,
walkNodes(f.body(), lc),
walkNodes(continueTarget, lc)),
lc));
}
public CAstNode visit(Closure closure, WalkContext wc) {
fIdentityMapper.mapLocalAnonTypeToMethod(closure.closureDef().asType(), wc.getEnclosingMethod());
CAstEntity bodyEntity= walkClosureEntity(closure, closure.body(), wc);
CAstNode closureNode= makeNode(wc, closure.body(), CAstNode.FUNCTION_EXPR, fFactory.makeConstant(bodyEntity));
wc.addScopedEntity(closureNode, bodyEntity);
return closureNode;
}
public CAstNode visit(ClosureCall closureCall, WalkContext wc) {
MethodInstance instance = closureCall.closureInstance();
CAstNode[] children = new CAstNode[2 + instance.formalTypes().size()];
int i = 0;
children[i++] = walkNodes(closureCall.target(), wc);
MethodReference methodRef = fIdentityMapper.getMethodRef(instance);
int dummyPC = 0;
CallSiteReference callSiteRef = CallSiteReference.make(dummyPC, methodRef, IInvokeInstruction.Dispatch.VIRTUAL);
children[i++] = fFactory.makeConstant(callSiteRef);
for (final Expr arg : closureCall.arguments()) {
children[i++] = walkNodes(arg, wc);
}
CAstNode result = makeNode(wc, fFactory, closureCall, CAstNode.CALL, children);
wc.cfg().map(closureCall, result);
return result;
}
public CAstNode visit(ParExpr pe, WalkContext wc) {
return walkNodes(pe.expr(), wc);
}
public CAstNode visit(final AtStmt atStmt, final WalkContext context) {
return makeNode(context, atStmt, CAstNode.UNWIND,
makeNode(context, atStmt, CAstNode.BLOCK_STMT,
makeNode(context, X10CastNode.AT_STMT_ENTER, atStmt.position().startOf()),
walkNodes(atStmt.body(), context)),
makeNode(context, X10CastNode.AT_STMT_EXIT, atStmt.position().endOf()));
}
}
final class ClosureBodyEntity extends CodeBodyEntity {
private final CodeBodyContext fContext;
private final CAstNode fBodyAst;
private final CAstSourcePositionMap.Position fPosition;
private final ClosureBodyType fBodyType;
private final CAstType fEnclosingType;
private final String[] fArgumentNames;
private final CAstNode[] fArgDefaults;
public ClosureBodyEntity(final Map<CAstNode,CAstEntity> entities, final Closure node, final CodeBodyContext context,
final CAstNode bodyAst, final Type enclosingType, final String[] argumentNames,
final CAstNode[] argDefaults) {
super(entities);
fContext= context;
fBodyAst= bodyAst;
fPosition= makePosition(node.position());
fEnclosingType= getTypeDict().getCAstTypeFor(enclosingType);
fBodyType= new ClosureBodyType(node.closureDef().asType(), fEnclosingType);
this.fArgumentNames = argumentNames;
this.fArgDefaults = argDefaults;
}
public CAstNode getAST() {
return fBodyAst;
}
public int getArgumentCount() {
return fArgumentNames.length;
}
public CAstNode[] getArgumentDefaults() {
return fArgDefaults;
}
public String[] getArgumentNames() {
return fArgumentNames;
}
public CAstControlFlowMap getControlFlow() {
return fContext.cfg();
}
public int getKind() {
return X10CAstEntity.CLOSURE_BODY;
}
public String getName() {
return "apply";
}
public CAstNodeTypeMap getNodeTypeMap() {
return fContext.getNodeTypeMap();
}
public CAstSourcePositionMap.Position getPosition() {
return fPosition;
}
public Collection getQualifiers() {
return Collections.EMPTY_LIST;
}
public CAstSourcePositionMap getSourceMap() {
return fContext.pos();
}
public CAstType getType() {
return fBodyType;
}
}
private final class ClosureBodyType implements CAstType.Method {
private final FunctionType closureType;
private List<CAstType> argTypes;
private List<CAstType> excTypes;
private CAstType returnType;
private CAstType enclosingType;
public ClosureBodyType(FunctionType cType, CAstType enclosingType) {
closureType= cType;
this.enclosingType= enclosingType;
}
public int getArgumentCount() {
return getArgumentTypes().size();
}
private List<CAstType> mapTypes(List<Type> types) {
List<CAstType> castTypes= new ArrayList<CAstType>();
for(Iterator iter= types.iterator(); iter.hasNext(); ) {
Type type= (Type) iter.next();
CAstType castType= getTypeDict().getCAstTypeFor(type);
castTypes.add(castType);
}
return castTypes;
}
public List getArgumentTypes() {
if (argTypes == null) {
argTypes= mapTypes(closureType.argumentTypes());
}
return argTypes;
}
public Collection getExceptionTypes() {
return Collections.EMPTY_LIST;
/* there are not checked exceptions in X10
if (excTypes == null) {
excTypes= mapTypes(closureType.throwTypes());
}
return excTypes;
*/
}
public CAstType getReturnType() {
if (returnType == null) {
returnType= getTypeDict().getCAstTypeFor(closureType.returnType());
}
return returnType;
}
public String getName() {
return ""; // Closures have no names
}
public Collection getSupertypes() {
return Collections.EMPTY_LIST;
}
public CAstType getDeclaringType() {
return enclosingType;
}
}
protected CAstNode walkNodes(Node n, WalkContext context) {
if (n == null) return fFactory.makeNode(CAstNode.EMPTY);
return X10ASTTraverser.visit(n, (X10TranslatorVisitor) getTranslator(), context);
}
protected CAstEntity walkEntity(final Node rootNode, final WalkContext context) {
if (rootNode instanceof TypeDecl) {
return new TypeDeclarationCAstEntity(makePosition(rootNode.position()), (TypeDecl) rootNode);
} else if (rootNode instanceof ProcedureDecl) {
// We need to have a specialization for the case of exploded vars definition and initialization.
final ProcedureDecl pd = (ProcedureDecl) rootNode;
final Map<CAstNode, CAstEntity> memberEntities = new LinkedHashMap<CAstNode, CAstEntity>();
final MethodContext mc = new MethodContext(pd.procedureInstance().asInstance(), memberEntities, context);
CAstNode procedureAST = null;
if (! pd.flags().flags().isAbstract()) {
procedureAST = walkNodes(pd, mc);
}
final List<Formal> formals = pd.formals();
final String[] argNames;
int i = 0;
if (! pd.flags().flags().isStatic()) {
argNames = new String[formals.size() + 1];
argNames[i++] = "this";
} else {
argNames = new String[formals.size()];
}
final Collection<CAstNode> bodyNodes = new ArrayList<CAstNode>();
for (final Formal formal : formals) {
argNames[i++] = formal.name().toString();
if (formal instanceof X10Formal) {
final X10Formal x10Formal = (X10Formal) formal;
if (x10Formal.hasExplodedVars()) {
int j = 0;
for (final Formal explodedVarFormal : x10Formal.vars()) {
bodyNodes.add(createExplodedVarInitialization(mc, formal, explodedVarFormal, j++));
}
}
}
}
final CAstNode newBodyAst;
if (bodyNodes.isEmpty()) {
newBodyAst = procedureAST;
} else {
// We want to access directly to the block statement.
bodyNodes.add(procedureAST.getChild(0).getChild(0));
newBodyAst = makeNode(mc, fFactory, pd, CAstNode.LOCAL_SCOPE,
makeNode(mc, fFactory, pd, CAstNode.BLOCK_STMT,
bodyNodes.toArray(new CAstNode[bodyNodes.size()])));
}
return new ProcedureEntity(newBodyAst, fTypeSystem, pd.procedureInstance().asInstance(), argNames, memberEntities, mc);
} else {
return SUPER_walkEntity(rootNode, context);
}
}
final class TypeDeclarationCAstEntity implements CAstEntity {
TypeDeclarationCAstEntity(final CAstSourcePositionMap.Position position, final TypeDecl typeDecl) {
this.fPosition = position;
this.fTypeDecl = typeDecl;
}
public CAstNode getAST() {
// No AST node
return null;
}
public Map<CAstNode, Collection<CAstEntity>> getAllScopedEntities() {
return Collections.emptyMap();
}
public int getArgumentCount() {
return 0;
}
public CAstNode[] getArgumentDefaults() {
return new CAstNode[0];
}
public String[] getArgumentNames() {
return new String[0];
}
public CAstControlFlowMap getControlFlow() {
// No Control Flow Map
return null;
}
public int getKind() {
return CAstEntity.TYPE_ENTITY;
}
public String getName() {
return this.fTypeDecl.name().toString();
}
public CAstNodeTypeMap getNodeTypeMap() {
return null;
}
public CAstSourcePositionMap.Position getPosition() {
return this.fPosition;
}
public Collection getQualifiers() {
return mapFlagsToQualifiers(this.fTypeDecl.typeDef().flags());
}
public Iterator getScopedEntities(CAstNode construct) {
return null;
}
public String getSignature() {
final StringBuilder sb = new StringBuilder();
sb.append('L').append(getName().replace('.', '/')).append(';');
return sb.toString();
}
public CAstSourcePositionMap getSourceMap() {
// No source map
return null;
}
public CAstType getType() {
return new CAstType() {
public String getName() {
return fTypeDecl.name().toString();
}
public Collection getSupertypes() {
return Collections.EMPTY_LIST;
}
};
}
private final CAstSourcePositionMap.Position fPosition;
private final TypeDecl fTypeDecl;
}
}