/*
* This file is part of the X10 project (http://x10-lang.org).
*
* This file is licensed to You under the Eclipse Public License (EPL);
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* (C) Copyright IBM Corporation 2006-2010.
*/
package x10.ast;
import java.util.Collections;
import java.util.List;
import polyglot.ast.Block;
import polyglot.ast.Expr;
import polyglot.ast.Expr_c;
import polyglot.ast.Node;
import polyglot.ast.NodeFactory;
import polyglot.ast.Term;
import polyglot.ast.Formal;
import polyglot.types.Context;
import polyglot.types.SemanticException;
import polyglot.types.Type;
import polyglot.types.Types;
import polyglot.util.CodeWriter;
import polyglot.util.CollectionUtil;
import polyglot.util.Position;
import polyglot.util.InternalCompilerError;
import polyglot.visit.CFGBuilder;
import polyglot.visit.ContextVisitor;
import polyglot.visit.NodeVisitor;
import polyglot.visit.PrettyPrinter;
import polyglot.visit.PruningVisitor;
import polyglot.visit.ReachChecker;
import polyglot.visit.TypeBuilder;
import x10.constraint.XTerm;
import x10.constraint.XFailure;
import x10.types.ClosureDef;
import x10.types.constants.ConstantValue;
import x10.types.constraints.ConstraintManager;
import x10.types.constraints.XConstrainedTerm;
import x10.types.constraints.CConstraint;
import polyglot.types.Context;
import polyglot.types.TypeSystem;
import x10.types.checker.Converter;
import x10.types.checker.PlaceChecker;
import x10.errors.Errors;
import x10.extension.X10Del;
import x10.extension.X10Ext;
/** A <code>AtExpr</code> is a representation of the X10 at construct:
* <code>at (place) { expression }<code>
* stmts are used to represent the fully exploded version of the expression
* as might be needed in order to inline array expressions.
* @author ??
* @author vj 08/30/09 - Refactored out PlacedClosure.
*/
public class AtExpr_c extends Closure_c implements AtExpr {
protected Expr place;
protected List<Node> captures;
public AtExpr_c(NodeFactory nf, Position p, Expr place, Block body) {
this(nf, p, place, null, body);
}
public AtExpr_c(NodeFactory nf, Position p, Expr place, List<Node> captures, Block body) {
super(nf, p, Collections.<Formal>emptyList(), nf.UnknownTypeNode(Position.COMPILER_GENERATED), null, null, body);
this.place = place;
this.captures = captures;
}
public List<Node> captures() {
return captures;
}
public AtExpr_c captures(List<Node> captures) {
AtExpr_c n = (AtExpr_c) copy();
n.captures = captures;
return n;
}
/** Get the RemoteActivity's place. */
public Expr place() {
return place;
}
/** Set the RemoteActivity's place. */
public AtExpr_c place(Expr place) {
if (place == this.place) return this;
assert place!=null;
AtExpr_c n = (AtExpr_c) copy();
n.place = place;
return n;
}
/** Visit the children of the expression. */
public Node visitChildren(NodeVisitor v) {
Expr place = (Expr) visitChild(this.place, v);
AtExpr_c n = (AtExpr_c) superVisitChildren(v);
if (n.place != place) {
if (n == this) n = (AtExpr_c) copy();
n.place = place;
}
return n;
}
private Node superVisitChildren(NodeVisitor v) {
return super.visitChildren(v);
}
@Override
public Node buildTypesOverride(TypeBuilder tb) {
AtExpr_c n = (AtExpr_c) super.buildTypesOverride(tb);
ClosureDef cd = n.closureDef();
cd.setPlaceTerm(null); // will be overwritten during typechecking
return n;
}
@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;
}
ContextVisitor childtc = (ContextVisitor) v;
Expr place = (Expr) visitChild(this.place, childtc);
place = Converter.attemptCoercion(tc, place, ts.Place());
if (place == null) {
Errors.issue(tc.job(),
new Errors.AtArgMustBePlace(this.place, ts.Place(), this.place.position()));
place = tc.nodeFactory().Here(this.place.position()).type(ts.Place());
}
Context c = tc.context();
ClosureDef def = (ClosureDef) this.codeDef();
if (def.placeTerm() == null) {
XConstrainedTerm placeTerm;
CConstraint d = ConstraintManager.getConstraintSystem().makeCConstraint();
XTerm term = PlaceChecker.makePlace();
try {
placeTerm = XConstrainedTerm.instantiate(d, term);
} catch (XFailure z) {
throw new InternalCompilerError("Cannot construct placeTerm from term and constraint.");
}
try {
XConstrainedTerm realPlaceTerm = PlaceChecker.computePlaceTerm(place, tc.context(), ts);
d.addBinding(placeTerm, realPlaceTerm);
} catch (SemanticException se) { }
def.setPlaceTerm(placeTerm);
}
// now that placeTerm is computed for this node, install it in the context
// and continue visiting children
Context oldC = c;
c = super.enterChildScope(this.body, childtc.context());
XConstrainedTerm pt = def.placeTerm();
if (pt != null) {
if (c == oldC)
c = c.pushBlock();
c.setPlace(pt);
}
AtExpr_c n = this.place(place);
n = (AtExpr_c) n.superVisitChildren(childtc.context(c));
List<AnnotationNode> oldAnnotations = ((X10Ext)n.ext()).annotations();
if (oldAnnotations != null && !oldAnnotations.isEmpty()) {
List<AnnotationNode> newAnnotations = visitList(oldAnnotations, v);
if (! CollectionUtil.allEqual(oldAnnotations, newAnnotations)) {
n = (AtExpr_c) ((X10Del) n.del()).annotations(newAnnotations);
}
}
return tc.leave(parent, this, n, childtc);
}
@Override
public Node typeCheck(ContextVisitor tc) {
AtExpr_c n = (AtExpr_c) super.typeCheck(tc);
Type t = n.returnType().type();
Context c = super.enterChildScope(body, tc.context());
ClosureDef def = (ClosureDef) codeDef();
XConstrainedTerm pt = def.placeTerm();
t = PlaceChecker.ReplaceHereByPlaceTerm(t, pt);
return n.type(t);
}
@Override
public Context enterScope(Context c) {
// c = c.pushBlock();
c = c.pushAt(closureDef);
c.x10Kind = Context.X10Kind.At;
return c;
}
@Override
public Context enterChildScope(Node child, Context c) {
if (child == this.place) return c.pop();
return super.enterChildScope(child, c);
}
/**
* Return the first (sub)term performed when evaluating this
* term.
*/
public Term firstChild() {
return returnType;
}
/**
* Visit this term in evaluation order.
*/
public <S> List<S> acceptCFG(CFGBuilder v, List<S> succs) {
v.visitCFG(returnType, place, ENTRY);
// If building the CFG for the enclosing code, don't thread
// in the closure body. Otherwise, we're building the CFG
// for the closure itself.
if (! succs.isEmpty()) {
v.visitCFG(place, this, EXIT);
}
else {
v.visitCFG(place, body, ENTRY);
v.visitCFG(body, this, EXIT);
}
/*
v.visitCFG(returnType, FlowGraph.EDGE_KEY_TRUE, body, ENTRY,
FlowGraph.EDGE_KEY_FALSE, this, EXIT);
*/
return succs;
}
public String toString() {
return "(#" + hashCode() + // todo: using hashCode leads to non-determinism in the output of the compiler
") at[" + returnType + "](" + place + ") " + body;
}
/** Write the expression to an output file. */
public void prettyPrint(CodeWriter w, PrettyPrinter tr) {
w.write("at[");
printBlock(returnType, w, tr);
w.write("](");
printSubExpr(place, false, w, tr);
w.write(") ");
printBlock(body, w, tr);
}
public boolean isConstant() {
return false;
}
public ConstantValue constantValue() {
return null;
}
}