Search in sources :

Example 1 with ProductType

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);
}
Also used : ErrorType(edu.mit.csail.sdg.alloy4.ErrorType) ProductType(edu.mit.csail.sdg.ast.Type.ProductType) ProductType(edu.mit.csail.sdg.ast.Type.ProductType) ErrorWarning(edu.mit.csail.sdg.alloy4.ErrorWarning) ArrayList(java.util.ArrayList) List(java.util.List) JoinableList(edu.mit.csail.sdg.alloy4.JoinableList) PrimSig(edu.mit.csail.sdg.ast.Sig.PrimSig)

Example 2 with ProductType

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;
}
Also used : Sig(edu.mit.csail.sdg.ast.Sig) VisitQueryOnce(edu.mit.csail.sdg.ast.VisitQueryOnce) Field(edu.mit.csail.sdg.ast.Sig.Field) ExprCall(edu.mit.csail.sdg.ast.ExprCall) Err(edu.mit.csail.sdg.alloy4.Err) ProductType(edu.mit.csail.sdg.ast.Type.ProductType) ExprUnary(edu.mit.csail.sdg.ast.ExprUnary)

Example 3 with ProductType

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;
}
Also used : LinkedHashSet(java.util.LinkedHashSet) ErrorType(edu.mit.csail.sdg.alloy4.ErrorType) ProductType(edu.mit.csail.sdg.ast.Type.ProductType) DirectedGraph(edu.mit.csail.sdg.alloy4.DirectedGraph) ProductType(edu.mit.csail.sdg.ast.Type.ProductType) PrimSig(edu.mit.csail.sdg.ast.Sig.PrimSig)

Aggregations

ProductType (edu.mit.csail.sdg.ast.Type.ProductType)3 ErrorType (edu.mit.csail.sdg.alloy4.ErrorType)2 PrimSig (edu.mit.csail.sdg.ast.Sig.PrimSig)2 DirectedGraph (edu.mit.csail.sdg.alloy4.DirectedGraph)1 Err (edu.mit.csail.sdg.alloy4.Err)1 ErrorWarning (edu.mit.csail.sdg.alloy4.ErrorWarning)1 JoinableList (edu.mit.csail.sdg.alloy4.JoinableList)1 ExprCall (edu.mit.csail.sdg.ast.ExprCall)1 ExprUnary (edu.mit.csail.sdg.ast.ExprUnary)1 Sig (edu.mit.csail.sdg.ast.Sig)1 Field (edu.mit.csail.sdg.ast.Sig.Field)1 VisitQueryOnce (edu.mit.csail.sdg.ast.VisitQueryOnce)1 ArrayList (java.util.ArrayList)1 LinkedHashSet (java.util.LinkedHashSet)1 List (java.util.List)1