use of edu.mit.csail.sdg.ast.Type.ProductType in project org.alloytools.alloy by AlloyTools.
the class ExprBinary method resolve.
// ============================================================================================================//
/**
* {@inheritDoc}
*/
@Override
public Expr resolve(Type p, Collection<ErrorWarning> warns) {
if (errors.size() > 0)
return this;
ErrorWarning w = null;
Type a = left.type, b = right.type;
switch(op) {
case MUL:
case DIV:
case REM:
case LT:
case LTE:
case GT:
case GTE:
case SHL:
case SHR:
case SHA:
case NOT_LTE:
case NOT_GTE:
case NOT_LT:
case NOT_GT:
{
a = (b = Type.smallIntType());
break;
}
case AND:
case OR:
case IFF:
case IMPLIES:
{
a = (b = Type.FORMULA);
break;
}
case EQUALS:
case NOT_EQUALS:
{
p = a.intersect(b);
if (p.hasTuple()) {
a = p;
b = p;
} else {
a = a.pickCommonArity(b);
b = b.pickCommonArity(a);
}
// } else
if (warns == null) {
break;
} else if (left.type.hasTuple() && right.type.hasTuple() && !(left.type.intersects(right.type))) {
w = warn("== is redundant, because the left and right expressions are always disjoint.");
} else if (left.isSame(right)) {
w = warn("== is redundant, because the left and right expressions always have the same value.");
}
break;
}
case IN:
case NOT_IN:
{
a = a.pickCommonArity(b);
b = b.intersect(a);
if (warns == null)
break;
if (left.type.hasNoTuple() && right.type.hasNoTuple())
w = warn("Subset operator is redundant, because both subexpressions are always empty.");
else if (left.type.hasNoTuple())
w = warn("Subset operator is redundant, because the left subexpression is always empty.");
else if (right.type.hasNoTuple())
w = warn("Subset operator is redundant, because the right subexpression is always empty.");
else if (b.hasNoTuple())
w = warn("Subset operator is redundant, because the left and right subexpressions are always disjoint.");
else if (left.isSame(right))
w = warn("Subset operator is redundant, because the left and right expressions always have the same value.");
break;
}
case INTERSECT:
{
a = a.intersect(p);
b = b.intersect(p);
if (warns != null && type.hasNoTuple())
w = warn("& is irrelevant because the two subexpressions are always disjoint.");
break;
}
case IPLUS:
case IMINUS:
{
a = Type.smallIntType();
b = Type.smallIntType();
break;
}
case PLUSPLUS:
case PLUS:
{
a = a.intersect(p);
b = b.intersect(p);
// b=Type.makeInt(b); }
if (warns == null)
break;
if (a == EMPTY && b == EMPTY)
w = warn(this + " is irrelevant since both subexpressions are redundant.", p);
else if (a == EMPTY)
w = warn(this + " is irrelevant since the left subexpression is redundant.", p);
else if (b == EMPTY || (op == Op.PLUSPLUS && !right.type.canOverride(left.type)))
w = warn(this + " is irrelevant since the right subexpression is redundant.", p);
break;
}
case MINUS:
{
a = p;
b = p.intersect(b);
// } else
if (warns != null && (type.hasNoTuple() || b.hasNoTuple())) {
w = warn("- is irrelevant since the right expression is redundant.", p);
}
break;
}
case JOIN:
{
if (warns != null && type.hasNoTuple())
w = warn("The join operation here always yields an empty set.");
a = (b = EMPTY);
for (ProductType aa : left.type) for (ProductType bb : right.type) if (p.hasArity(aa.arity() + bb.arity() - 2)) {
PrimSig j = aa.get(aa.arity() - 1).intersect(bb.get(0));
if (j != Sig.NONE)
for (ProductType cc : p.intersect(aa.join(bb))) if (!cc.isEmpty()) {
List<PrimSig> v = new ArrayList<PrimSig>(cc.arity() + 1);
for (int i = 0; i < cc.arity(); i++) v.add(cc.get(i));
v.add(aa.arity() - 1, j);
a = a.merge(Type.make(v, 0, aa.arity()));
b = b.merge(Type.make(v, aa.arity() - 1, v.size()));
}
}
if (a == EMPTY || b == EMPTY) {
// Continue the best we can; we
// should have issued a
// relevance warning elsewhere
// already.
a = (b = EMPTY);
for (ProductType aa : left.type) for (ProductType bb : right.type) if (p.hasArity(aa.arity() + bb.arity() - 2) && aa.get(aa.arity() - 1).intersects(bb.get(0))) {
a = a.merge(aa);
b = b.merge(bb);
}
}
if (a == EMPTY || b == EMPTY) {
// Continue the best we can; we
// should have issued a
// relevance warning elsewhere
// already.
a = (b = EMPTY);
for (ProductType aa : left.type) for (ProductType bb : right.type) if (p.hasArity(aa.arity() + bb.arity() - 2)) {
a = a.merge(aa);
b = b.merge(bb);
}
}
break;
}
case DOMAIN:
{
// leftType such that r1<:r2 in parentType}
if (warns != null && type.hasNoTuple())
w = warn("<: is irrelevant because the result is always empty.");
Type leftType = EMPTY, rightType = EMPTY;
for (ProductType aa : a) if (aa.arity() == 1)
for (ProductType bb : b) if (p.hasArity(bb.arity()))
for (ProductType cc : p.intersect(bb.columnRestrict(aa.get(0), 0))) if (!cc.isEmpty()) {
leftType = leftType.merge(cc, 0, 1);
rightType = rightType.merge(cc);
}
if (leftType == EMPTY || rightType == EMPTY) {
// We try to
// proceed the
// best we can
leftType = a.extract(1);
rightType = b.pickCommonArity(p);
}
a = leftType;
b = rightType;
break;
}
case RANGE:
{
// leftType such that r1:>r2 in parentType}
if (warns != null && type.hasNoTuple())
w = warn(":> is irrelevant because the result is always empty.");
Type leftType = EMPTY, rightType = EMPTY;
for (ProductType bb : b) if (bb.arity() == 1)
for (ProductType aa : a) if (p.hasArity(aa.arity()))
for (ProductType cc : p.intersect(aa.columnRestrict(bb.get(0), aa.arity() - 1))) if (!cc.isEmpty()) {
leftType = leftType.merge(cc);
rightType = rightType.merge(cc, cc.arity() - 1, cc.arity());
}
if (leftType == EMPTY || rightType == EMPTY) {
// We try to
// proceed the
// best we can
leftType = a.pickCommonArity(p);
rightType = b.extract(1);
}
a = leftType;
b = rightType;
break;
}
default:
{
// leftType such that r1->r2 in parentType}
if (warns == null) {
// do nothing
} else if (a.hasTuple()) {
if (b.hasNoTuple())
w = warn("The left expression of -> is irrelevant because the right expression is always empty.");
} else {
if (b.hasTuple())
w = warn("The right expression of -> is irrelevant because the left expression is always empty.");
}
Type leftType = EMPTY, rightType = EMPTY;
for (ProductType aa : a) if (!aa.isEmpty())
for (ProductType bb : b) if (!bb.isEmpty() && p.hasArity(aa.arity() + bb.arity()))
for (ProductType cc : p.intersect(aa.product(bb))) if (!cc.isEmpty()) {
leftType = leftType.merge(cc, 0, aa.arity());
rightType = rightType.merge(cc, aa.arity(), cc.arity());
}
// relevance warning already.
if (leftType == EMPTY || rightType == EMPTY) {
leftType = a;
rightType = b;
}
a = leftType;
b = rightType;
}
}
Expr left = this.left.resolve(a, warns);
Expr right = this.right.resolve(b, warns);
if (w != null)
warns.add(w);
return (left == this.left && right == this.right) ? this : op.make(pos, closingBracket, left, right);
}
use of edu.mit.csail.sdg.ast.Type.ProductType in project org.alloytools.alloy by AlloyTools.
the class CompUtil method areIntsUsed.
// =============================================================================================================//
/**
* Whether or not Int appears in the relation types found in these sigs
*/
public static boolean areIntsUsed(Iterable<Sig> sigs, Command cmd) {
/* check for Int-typed relations */
for (Sig s : sigs) {
for (Field f : s.getFields()) {
for (ProductType pt : f.type()) {
for (int k = 0; k < pt.arity(); k++) {
if (pt.get(k) == SIGINT || pt.get(k) == SEQIDX)
return true;
}
}
}
}
if (cmd == null)
return false;
/* check expressions; look for CAST2SIGING (Int[]) */
try {
Object intTriggerNode;
intTriggerNode = cmd.formula.accept(new VisitQueryOnce<Object>() {
@Override
public Object visit(ExprCall x) throws Err {
// Int[]
if (x.fun.label.startsWith("integer/"))
return null;
return super.visit(x);
}
@Override
public Object visit(ExprUnary x) throws Err {
if (x.op == Op.CAST2SIGINT)
return x;
return super.visit(x);
}
});
if (intTriggerNode != null)
return true;
} catch (Err e) {
}
return false;
}
use of edu.mit.csail.sdg.ast.Type.ProductType in project org.alloytools.alloy by AlloyTools.
the class ExprUnary method resolveClosure.
// ============================================================================================================//
/**
* Helper method that computes the relevant type for a closure expression.
* <p>
* Return Value == { c1->c2 | c1->c2 in childType, AND exists p1->p2 in
* parentType where p1..c1..c2..p2 is a path in the closure graph }
* <p>
* We need to do this because of situations like this follow: Suppose e's type
* is "A->B + B->C". Therefore, ^e = A->B + B->C + A->C which makes sense. But
* as we compute the relevance type back down, we may have lost some entries,
* and possibly end up with only A->B + A->C so we need to rediscover the
* relevant edges.
*/
private static Type resolveClosure(Type parent, Type child) {
LinkedHashSet<PrimSig> nodes = new LinkedHashSet<PrimSig>();
DirectedGraph<PrimSig> graph = new DirectedGraph<PrimSig>();
// For each (v1->v2) in childType, add (v1->v2) into the graph.
for (ProductType c : child) if (c.arity() == 2) {
PrimSig a = c.get(0), b = c.get(1);
nodes.add(a);
nodes.add(b);
graph.addEdge(a, b);
}
// edges v1->v2 and v2->v1.
for (PrimSig a : nodes) for (PrimSig b : nodes) if (a != b && a.intersects(b))
graph.addEdge(a, b);
// them.
for (ProductType p : parent) if (p.arity() == 2) {
PrimSig a = p.get(0), b = p.get(1);
// Add edges between a and all its subtypes and supertypes
if (!nodes.contains(a)) {
for (PrimSig x : nodes) if (a.intersects(x)) {
graph.addEdge(a, x);
graph.addEdge(x, a);
}
nodes.add(a);
}
// Add edges between b and all its subtypes and supertypes
if (!nodes.contains(b)) {
for (PrimSig x : nodes) if (b.intersects(x)) {
graph.addEdge(b, x);
graph.addEdge(x, b);
}
nodes.add(b);
}
}
// For each c1->c2 in childType, add c1->c2 into the finalType if there
// exists p1->p2 in parentType
// such that p1->..->c1->c2->..->p2 is a path in the graph.
Type answer = Type.EMPTY;
for (ProductType c : child) if (c.arity() == 2) {
PrimSig c1 = c.get(0), c2 = c.get(1);
for (ProductType p : parent) if (p.arity() == 2) {
PrimSig p1 = p.get(0), p2 = p.get(1);
if (graph.hasPath(p1, c1) && graph.hasPath(c2, p2)) {
answer = answer.merge(c);
break;
}
}
}
return answer;
}
Aggregations