001package org.clafer.ir;
002
003import org.clafer.common.Check;
004
005/**
006 * left `op` right + offset
007 *
008 * @author jimmy
009 */
010public class IrCompare extends IrAbstractBool implements IrBoolExpr {
011
012    private final IrIntExpr left;
013    private final Op op;
014    private final IrIntExpr right;
015
016    IrCompare(IrIntExpr left, Op op, IrIntExpr right, IrBoolDomain domain) {
017        super(domain);
018        this.left = Check.notNull(left);
019        this.op = Check.notNull(op);
020        this.right = Check.notNull(right);
021    }
022
023    public IrIntExpr getLeft() {
024        return left;
025    }
026
027    public Op getOp() {
028        return op;
029    }
030
031    public IrIntExpr getRight() {
032        return right;
033    }
034
035    @Override
036    public IrBoolExpr negate() {
037        switch (op) {
038            case Equal:
039                return new IrCompare(left, Op.NotEqual, right, getDomain().invert());
040            case NotEqual:
041                return new IrCompare(left, Op.Equal, right, getDomain().invert());
042            case LessThan:
043                return new IrCompare(right, Op.LessThanEqual, left, getDomain().invert());
044            case LessThanEqual:
045                return new IrCompare(right, Op.LessThan, left, getDomain().invert());
046            default:
047                throw new IllegalStateException();
048        }
049    }
050
051    @Override
052    public boolean isNegative() {
053        return false;
054    }
055
056    @Override
057    public <A, B> B accept(IrBoolExprVisitor<A, B> visitor, A a) {
058        return visitor.visit(this, a);
059    }
060
061    @Override
062    public <A, B> B accept(IrIntExprVisitor<A, B> visitor, A a) {
063        return visitor.visit(this, a);
064    }
065
066    @Override
067    public boolean equals(Object obj) {
068        if (obj instanceof IrCompare) {
069            IrCompare other = (IrCompare) obj;
070            return left.equals(other.left) && op.equals(other.op) && right.equals(other.right) && super.equals(other);
071        }
072        return false;
073    }
074
075    @Override
076    public int hashCode() {
077        // op.hashCode() can change between runs which makes the output change
078        // every time.
079        return left.hashCode() ^ op.ordinal() ^ right.hashCode();
080    }
081
082    @Override
083    public String toString() {
084        return left + " " + op.getSyntax() + " " + right;
085    }
086
087    public static enum Op {
088
089        Equal("="),
090        NotEqual("!="),
091        LessThan("<"),
092        LessThanEqual("<=");
093        private final String syntax;
094
095        Op(String syntax) {
096            this.syntax = syntax;
097        }
098
099        public String getSyntax() {
100            return syntax;
101        }
102
103        public boolean isEquality() {
104            switch (this) {
105                case Equal:
106                case NotEqual:
107                    return true;
108                default:
109                    return false;
110            }
111        }
112
113        public boolean isInequality() {
114            return !isEquality();
115        }
116    }
117}