package expression; import java.math.BigDecimal; import java.math.BigInteger; import java.util.List; /** * @author Doschennikov Nikita (me@fymio.us) */ public abstract class AbstractBinaryOperation extends AbstractExpression { protected final AbstractExpression left; protected final AbstractExpression right; protected AbstractBinaryOperation( AbstractExpression left, AbstractExpression right ) { this.left = left; this.right = right; } protected abstract String getOperator(); protected abstract int getPriority(); protected abstract boolean isRightAssoc(); protected abstract int applyInt(int a, int b); protected abstract BigInteger applyBi(BigInteger a, BigInteger b); protected abstract BigDecimal applyBd(BigDecimal a, BigDecimal b); @Override public int evaluate(int x) { return applyInt(left.evaluate(x), right.evaluate(x)); } @Override public int evaluate(int x, int y, int z) { return applyInt(left.evaluate(x, y, z), right.evaluate(x, y, z)); } @Override public int evaluate(List vars) { return applyInt(left.evaluate(vars), right.evaluate(vars)); } @Override public BigInteger evaluateBi(List vars) { return applyBi(left.evaluateBi(vars), right.evaluateBi(vars)); } @Override public BigDecimal evaluateBd(List vars) { return applyBd(left.evaluateBd(vars), right.evaluateBd(vars)); } @Override public String toString() { return "(" + left + " " + getOperator() + " " + right + ")"; } @Override public String toMiniString() { return miniLeft() + " " + getOperator() + " " + miniRight(); } private String miniLeft() { if ( left instanceof AbstractBinaryOperation op && op.getPriority() < getPriority() ) { return "(" + op.toMiniString() + ")"; } return left.toMiniString(); } private String miniRight() { if (right instanceof AbstractBinaryOperation op) { boolean samePriority = op.getPriority() == getPriority(); boolean lowerPriority = op.getPriority() < getPriority(); boolean needParens = lowerPriority || (samePriority && isRightAssoc()) || (samePriority && op.isRightAssoc() && getPriority() > 1) || (samePriority && !getOperator().equals(op.getOperator()) && !op.isRightAssoc() && !isRightAssoc()); if (needParens) { return "(" + op.toMiniString() + ")"; } } return right.toMiniString(); } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null || getClass() != obj.getClass()) return false; AbstractBinaryOperation other = (AbstractBinaryOperation) obj; return left.equals(other.left) && right.equals(other.right); } @Override public int hashCode() { return ( 31 * (31 * left.hashCode() + right.hashCode()) + getClass().hashCode() ); } }