コード例 #1
0
        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);
        }