use of edu.mit.csail.sdg.alloy4.Pos in project org.alloytools.alloy by AlloyTools.
the class A4SolutionReader method parseField.
/**
* Parse field.
*/
private Field parseField(String id) throws IOException, Err {
final XMLNode node = nmap.get(id);
if (node == null)
throw new IOException("Unknown FieldID " + id + " encountered.");
if (!node.is("field"))
throw new IOException("ID " + id + " is not a field.");
String label = label(node);
Pos isPrivate = yes(node, "private") ? Pos.UNKNOWN : null;
Pos isMeta = yes(node, "meta") ? Pos.UNKNOWN : null;
Expr type = null;
for (XMLNode sub : node) if (sub.is("types")) {
Expr t = parseType(sub);
if (type == null)
type = t;
else
type = type.plus(t);
}
int arity;
if (type == null || (arity = type.type().arity()) < 2)
throw new IOException("Field " + label + " is maltyped.");
String parentID = node.getAttribute("parentID");
Sig parent = id2sig.get(parentID);
if (parent == null)
throw new IOException("ID " + parentID + " is not a sig.");
Field field = null;
for (Field f : parent.getFields()) if (f.label.equals(label) && f.type().arity() == arity && choices.contains(f)) {
field = f;
choices.remove(f);
break;
}
if (field == null)
field = parent.addTrickyField(Pos.UNKNOWN, isPrivate, null, null, isMeta, new String[] { label }, UNIV.join(type))[0];
TupleSet ts = parseTuples(node, arity);
expr2ts.put(field, ts);
return field;
}
use of edu.mit.csail.sdg.alloy4.Pos in project org.alloytools.alloy by AlloyTools.
the class ExprBadCall method span.
/**
* {@inheritDoc}
*/
@Override
public Pos span() {
Pos p = span;
if (p == null) {
p = pos.merge(closingBracket);
for (Expr a : args) p = p.merge(a.span());
span = p;
}
return p;
}
use of edu.mit.csail.sdg.alloy4.Pos 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.alloy4.Pos in project org.alloytools.alloy by AlloyTools.
the class ExprCall method getSubnodes.
/**
* {@inheritDoc}
*/
@Override
public List<? extends Browsable> getSubnodes() {
if (args.size() == 0) {
Expr b = fun.getBody();
return Util.asList(make(b.pos(), b.span(), b.getHTML(), b.getSubnodes()));
}
Pos p = pos;
if (p == Pos.UNKNOWN)
p = span();
Browsable f = make(p, p, (fun.isPred ? "<b>pred</b> " : "<b>fun</b> ") + fun.label, fun.getSubnodes());
Browsable a = make(span(), span(), "<b>" + args.size() + " argument" + (args.size() == 1 ? "</b>" : "s</b>"), args);
return Util.asList(f, a);
}
use of edu.mit.csail.sdg.alloy4.Pos in project org.alloytools.alloy by AlloyTools.
the class ExprCall method make.
// ============================================================================================================//
/**
* Constructs an ExprCall node with the given predicate/function "fun" and the
* list of arguments "args".
*/
public static Expr make(Pos pos, Pos closingBracket, Func fun, List<Expr> args, long extraPenalty) {
if (extraPenalty < 0)
extraPenalty = 0;
if (args == null)
args = ConstList.make();
long weight = extraPenalty;
boolean ambiguous = false;
JoinableList<Err> errs = emptyListOfErrors;
TempList<Expr> newargs = new TempList<Expr>(args.size());
if (args.size() != fun.count()) {
errs = errs.make(new ErrorSyntax(pos, "" + fun + " has " + fun.count() + " parameters but is called with " + args.size() + " arguments."));
}
for (int i = 0; i < args.size(); i++) {
final int a = (i < fun.count()) ? fun.get(i).type.arity() : 0;
final Expr x = args.get(i).typecheck_as_set();
ambiguous = ambiguous || x.ambiguous;
errs = errs.make(x.errors);
weight = weight + x.weight;
if (x.mult != 0)
errs = errs.make(new ErrorSyntax(x.span(), "Multiplicity expression not allowed here."));
if (a > 0 && x.errors.isEmpty() && !x.type.hasArity(a))
errs = errs.make(new ErrorType(x.span(), "This should have arity " + a + " but instead its possible type(s) are " + x.type));
newargs.add(x);
}
Type t = Type.FORMULA;
if (!fun.isPred && errs.size() == 0) {
final Type tt = fun.returnDecl.type;
try {
// This provides a limited form of polymorphic function,
// by using actual arguments at each call site to derive a
// tighter bound on the return value.
DeduceType d = new DeduceType();
for (int i = 0; i < args.size(); i++) {
ExprVar param = fun.get(i);
d.env.put(param, newargs.get(i).type.extract(param.type.arity()));
}
t = fun.returnDecl.accept(d);
if (t == null || t.is_int() || t.is_bool || t.arity() != tt.arity())
// Just in case an error occurred...
t = tt;
} catch (Throwable ex) {
// Just in case an error occurred...
t = tt;
}
}
return new ExprCall(pos, closingBracket, ambiguous, t, fun, newargs.makeConst(), extraPenalty, weight, errs);
}
Aggregations