package x10.ast;
import java.util.List;
import polyglot.ast.Expr;
import polyglot.ast.Expr_c;
import polyglot.ast.If;
import polyglot.ast.If_c;
import polyglot.ast.Node;
import polyglot.ast.NodeList;
import polyglot.ast.Stmt;
import polyglot.ast.Term;
import polyglot.types.Context;
import polyglot.types.SemanticException;
import polyglot.types.Type;
import polyglot.types.TypeSystem;
import polyglot.types.Types;
import polyglot.util.CodeWriter;
import polyglot.util.CollectionUtil; import x10.util.CollectionFactory;
import polyglot.util.Position;
import polyglot.visit.CFGBuilder;
import polyglot.visit.ContextVisitor;
import polyglot.visit.NodeVisitor;
import polyglot.visit.PrettyPrinter;
import polyglot.visit.PruningVisitor;
import x10.errors.Errors;
import x10.extension.X10Del;
import x10.extension.X10Ext;
import x10.types.ClosureDef;
import polyglot.types.Context;
import polyglot.types.TypeSystem;
import x10.types.checker.PlaceChecker;
import x10.types.constraints.XConstrainedTerm;
import x10.visit.X10TypeChecker;
public class FinishExpr_c extends Expr_c implements FinishExpr {
Expr reducer;
Stmt body;
/**
* @param pos
*/
public FinishExpr_c(Position pos, Expr r, Stmt body) {
super(pos);
this.reducer = r;
this.body = body;
}
public Expr reducer() {
return reducer;
}
public Stmt body() {
return body;
}
/*
* (non-Javadoc)
*
* @see polyglot.ast.Term_c#acceptCFG(polyglot.visit.CFGBuilder,
* java.util.List)
*/
@Override
public <S> List<S> acceptCFG(CFGBuilder v, List<S> succs) {
v.visitCFG(reducer, body, ENTRY);
v.visitCFG(body, this, EXIT);
return succs;
}
@Override
public Node typeCheckOverride(Node parent, ContextVisitor tc) {
TypeSystem ts = (TypeSystem) tc.typeSystem();
NodeVisitor v = tc.enter(parent, this);
if (v instanceof PruningVisitor) {
return this;
}
// Check that reducer is a Reducer, throwing an exception if not.
Expr e = (Expr) visitChild(reducer, v);
Type r = Types.reducerType(e.type());
if (r == null) {
Errors.issue(tc.job(), new Errors.IsNotReducible(e, e.position()), this);
r = ts.unknownType(e.position());
}
Node tmpNode = reconstruct(e,body).type(r);
Context childScope = tmpNode.enterChildScope(body, tc.context());
ContextVisitor childVisitor = tc.context(childScope);
Stmt b = (Stmt) tmpNode.visitChild(body, childVisitor);
Node n = reconstruct(e,b).type(r);
List<AnnotationNode> oldAnnotations = ((X10Ext) ext()).annotations();
if (oldAnnotations == null || oldAnnotations.isEmpty()) {
return n;
}
List<AnnotationNode> newAnnotations = node().visitList(oldAnnotations, v);
if (! CollectionUtil.allEqual(oldAnnotations, newAnnotations)) {
return ((X10Del) n.del()).annotations(newAnnotations);
}
return n;
}
/**
* When visiting the body set the collectingFinishType in the context to be
* the type of the reducer.
*/
@Override
public Context enterChildScope(Node child, Context c) {
Context oldC=c;
Context xc = (Context) super.enterChildScope(child, c);
if (child == body) {
// Push T, not Reducible[T].
Type type = reducer.type();
type = Types.reducerType(type);
if (type != null) {
if (c==oldC)
c=c.pushBlock();
xc.setCollectingFinishScope(type);
}
addDecls(xc);
}
return xc;
}
/** Type check the statement.
public Node typeCheck(ContextVisitor tc) {
// This must succeed, otherwise typeCheckOverride has already
// thrown an exception.
Type reducerBase = X10TypeMixin.reducerType(reducer.type());
assert reducerBase != null;
return type(reducerBase);
}
*/
/*
* (non-Javadoc)
*
* @see polyglot.ast.Term#firstChild()
*/
public Term firstChild() {
return reducer;
}
/** Set the consequent of the statement. */
public FinishExpr reconstruct(Expr e, Stmt b) {
if (e == reducer && body == b)
return this;
FinishExpr_c n = (FinishExpr_c) copy();
n.reducer = e;
n.body = b;
return n;
}
/** Visit the children of the statement. */
public Node visitChildren(NodeVisitor v) {
Expr reducer = (Expr) visitChild(this.reducer, v);
Stmt body = (Stmt) visitChild(this.body, v);
return reconstruct(reducer, body);
}
public String toString() {
return "finish(" + reducer.toString() + ")" + body.toString();
}
public void prettyPrint(CodeWriter w, PrettyPrinter tr) {
w.write("finish (");
printBlock(reducer, w, tr);
w.write(")");
printBlock(body, w, tr);
}
}