/*===============================*/
/** {@inheritDoc} */
@Override public Object visit(ExprBinary x) throws Err {
Expr a=x.left, b=x.right;
Expression s, s2; IntExpression i; Formula f; Object obj;
switch(x.op) {
case IMPLIES: f=cform(a).not().or(cform(b)); return k2pos(f,x);
case IN: return k2pos(isIn(cset(a),b), x);
case NOT_IN: return k2pos(isIn(cset(a),b).not(), x);
case LT: i=cint(a); f=i.lt(cint(b)); return k2pos(f,x);
case LTE: i=cint(a); f=i.lte(cint(b)); return k2pos(f,x);
case GT: i=cint(a); f=i.gt(cint(b)); return k2pos(f,x);
case GTE: i=cint(a); f=i.gte(cint(b)); return k2pos(f,x);
case NOT_LT: i=cint(a); f=i.lt(cint(b)).not(); return k2pos(f,x);
case NOT_LTE: i=cint(a); f=i.lte(cint(b)).not(); return k2pos(f,x);
case NOT_GT: i=cint(a); f=i.gt(cint(b)).not(); return k2pos(f,x);
case NOT_GTE: i=cint(a); f=i.gte(cint(b)).not(); return k2pos(f,x);
case AND: f=cform(a); f=f.and(cform(b)); return k2pos(f,x);
case OR: f=cform(a); f=f.or(cform(b)); return k2pos(f,x);
case IFF: f=cform(a); f=f.iff(cform(b)); return k2pos(f,x);
case PLUSPLUS: s=cset(a); return s.override(cset(b));
case MUL: i=cint(a); return i.multiply(cint(b));
case DIV: i=cint(a); return i.divide(cint(b));
case REM: i=cint(a); return i.modulo(cint(b));
case SHL: i=cint(a); return i.shl(cint(b));
case SHR: i=cint(a); return i.shr(cint(b));
case SHA: i=cint(a); return i.sha(cint(b));
case PLUS:
obj = visitThis(a);
if (obj instanceof IntExpression) { i=(IntExpression)obj; return i.plus(cint(b)); }
s = (Expression)obj; return s.union(cset(b));
case MINUS:
// Special exception to allow "0-8" to not throw an exception, where 7 is the maximum allowed integer (when bitwidth==4)
// (likewise, when bitwidth==5, then +15 is the maximum allowed integer, and we want to allow 0-16 without throwing an exception)
if (a instanceof ExprConstant && ((ExprConstant)a).op==ExprConstant.Op.NUMBER && ((ExprConstant)a).num()==0)
if (b instanceof ExprConstant && ((ExprConstant)b).op==ExprConstant.Op.NUMBER && ((ExprConstant)b).num()==max+1)
return IntConstant.constant(min);
obj=visitThis(a);
if (obj instanceof IntExpression) { i=(IntExpression)obj; return i.minus(cint(b));}
s=(Expression)obj; return s.difference(cset(b));
case INTERSECT:
s=cset(a); return s.intersection(cset(b));
case ANY_ARROW_SOME: case ANY_ARROW_ONE: case ANY_ARROW_LONE:
case SOME_ARROW_ANY: case SOME_ARROW_SOME: case SOME_ARROW_ONE: case SOME_ARROW_LONE:
case ONE_ARROW_ANY: case ONE_ARROW_SOME: case ONE_ARROW_ONE: case ONE_ARROW_LONE:
case LONE_ARROW_ANY: case LONE_ARROW_SOME: case LONE_ARROW_ONE: case LONE_ARROW_LONE:
case ISSEQ_ARROW_LONE:
case ARROW:
s=cset(a); return s.product(cset(b));
case JOIN:
a=a.deNOP(); s=cset(a); s2=cset(b);
if (a instanceof Sig && ((Sig)a).isOne!=null && s2 instanceof BinaryExpression) {
BinaryExpression bin = (BinaryExpression)s2;
if (bin.op()==ExprOperator.PRODUCT && bin.left()==s) return bin.right();
}
return s.join(s2);
case EQUALS:
obj=visitThis(a);
if (obj instanceof IntExpression) { i=(IntExpression)obj; f=i.eq(cint(b));}
else { s=(Expression)obj; f=s.eq(cset(b)); }
return k2pos(f,x);
case NOT_EQUALS:
obj=visitThis(a);
if (obj instanceof IntExpression) { i=(IntExpression)obj; f=i.eq(cint(b)).not();}
else { s=(Expression)obj; f=s.eq(cset(b)).not(); }
return k2pos(f,x);
case DOMAIN:
s=cset(a);
s2=cset(b);