public override PrimitiveExpression Simplified(Grimoire grimoire, CalcTimer timer) { timer.ThrowIfTimedOut(); PrimitiveExpression primLeft = LeftSide.Simplified(grimoire, timer); timer.ThrowIfTimedOut(); PrimitiveExpression primRight = RightSide.Simplified(grimoire, timer); timer.ThrowIfTimedOut(); // type check switch (Operation) { case Operation.BinaryAnd: case Operation.BinaryOr: case Operation.BinaryXor: if (primLeft.Type == PrimitiveType.Decimal || primRight.Type == PrimitiveType.Decimal) { throw new SimplificationException( "Cannot perform a bitwise operation on a floating-point number.", this ); } break; default: break; } try { // mixed types? coerce if (primLeft.Type == PrimitiveType.IntegerLong) { if (primRight.Type == PrimitiveType.IntegerBig) { // IntegerLong < IntegerBig primLeft = new PrimitiveExpression(primLeft.Index, primLeft.Length, new BigInteger(primLeft.LongValue)); } else if (primRight.Type == PrimitiveType.Decimal) { // IntegerLong < Decimal primLeft = new PrimitiveExpression(primLeft.Index, primLeft.Length, (decimal)primLeft.LongValue); } } else if (primLeft.Type == PrimitiveType.IntegerBig) { if (primRight.Type == PrimitiveType.IntegerLong) { // IntegerBig > IntegerLong primRight = new PrimitiveExpression(primRight.Index, primRight.Length, new BigInteger(primRight.LongValue)); } else if (primRight.Type == PrimitiveType.Decimal) { // IntegerBig < Decimal primLeft = new PrimitiveExpression(primLeft.Index, primLeft.Length, (decimal)primLeft.BigIntegerValue); } } else if (primLeft.Type == PrimitiveType.Decimal) { if (primRight.Type == PrimitiveType.IntegerLong) { // Decimal > IntegerLong primRight = new PrimitiveExpression(primRight.Index, primRight.Length, (decimal)primRight.LongValue); } else if (primRight.Type == PrimitiveType.IntegerBig) { // Decimal > IntegerBig primRight = new PrimitiveExpression(primRight.Index, primRight.Length, (decimal)primRight.BigIntegerValue); } } } catch (OverflowException ex) { throw new SimplificationException(this, ex); } catch (DivideByZeroException ex) { throw new SimplificationException(this, ex); } catch (FunctionDomainException ex) { throw new SimplificationException(this, ex); } catch (TimeoutException ex) { throw new SimplificationException(this, ex); } timer.ThrowIfTimedOut(); Debug.Assert(primLeft.Type == primRight.Type); int newIndex = primLeft.Index; int newLength = primRight.Index + primRight.Length - primLeft.Index; try { switch (Operation) { case Operation.Add: return(BinaryOp( newIndex, newLength, primLeft, primRight, (a, b) => checked (a + b), (a, b) => checked (a + b), (a, b) => checked (a + b) )); case Operation.Divide: return(new PrimitiveExpression( newIndex, newLength, checked (primLeft.ToDecimal() / primRight.ToDecimal()) )); case Operation.IntegralDivide: return(BinaryOp( newIndex, newLength, primLeft, primRight, (a, b) => checked (a / b), (a, b) => checked (a / b), (a, b) => Math.Truncate(checked (a / b)) )); case Operation.Multiply: return(BinaryOp( newIndex, newLength, primLeft, primRight, (a, b) => checked (a * b), (a, b) => checked (a * b), (a, b) => checked (a * b) )); case Operation.Power: if (primLeft.Type == PrimitiveType.IntegerLong) { return(Pow(newIndex, newLength, primLeft.LongValue, primRight.LongValue, timer)); } else if (primLeft.Type == PrimitiveType.IntegerBig) { return(Pow(newIndex, newLength, primLeft.BigIntegerValue, primRight.BigIntegerValue, timer)); } else if (primLeft.Type == PrimitiveType.Decimal) { return(Pow(newIndex, newLength, primLeft.DecimalValue, primRight.DecimalValue, timer)); } break; case Operation.Remainder: return(BinaryOp( newIndex, newLength, primLeft, primRight, (a, b) => checked (a % b), (a, b) => checked (a % b), (a, b) => checked (a % b) )); case Operation.Subtract: return(BinaryOp( newIndex, newLength, primLeft, primRight, (a, b) => checked (a - b), (a, b) => checked (a - b), (a, b) => checked (a - b) )); case Operation.BinaryAnd: return(BinaryOp( newIndex, newLength, primLeft, primRight, (a, b) => checked (a & b), (a, b) => checked (a & b), null )); case Operation.BinaryOr: return(BinaryOp( newIndex, newLength, primLeft, primRight, (a, b) => checked (a | b), (a, b) => checked (a | b), null )); case Operation.BinaryXor: return(BinaryOp( newIndex, newLength, primLeft, primRight, (a, b) => checked (a ^ b), (a, b) => checked (a ^ b), null )); } } catch (OverflowException ex) { throw new SimplificationException(this, ex); } catch (DivideByZeroException ex) { throw new SimplificationException(this, ex); } catch (FunctionDomainException ex) { throw new SimplificationException(this, ex); } catch (TimeoutException ex) { throw new SimplificationException(this, ex); } throw new SimplificationException($"Cannot handle binary operator {Operation}.", this); }