private ConstantWrapper StrictNotEqual(ConstantWrapper left, ConstantWrapper right)
        {
            ConstantWrapper newLiteral = null;

            if (m_parser.Settings.IsModificationAllowed(TreeModifications.EvaluateNumericExpressions))
            {
                PrimitiveType leftType = left.PrimitiveType;
                if (leftType == right.PrimitiveType)
                {
                    // the values are the same type
                    switch (leftType)
                    {
                        case PrimitiveType.Null:
                            // null !== null is false
                            newLiteral = new ConstantWrapper(false, PrimitiveType.Boolean, null, m_parser);
                            break;

                        case PrimitiveType.Boolean:
                            // compare boolean values
                            newLiteral = new ConstantWrapper(left.ToBoolean() != right.ToBoolean(), PrimitiveType.Boolean, null, m_parser);
                            break;

                        case PrimitiveType.String:
                            // compare string ordinally
                            if (left.IsOkayToCombine && right.IsOkayToCombine)
                            {
                                newLiteral = new ConstantWrapper(string.CompareOrdinal(left.ToString(), right.ToString()) != 0, PrimitiveType.Boolean, null, m_parser);
                            }
                            break;

                        case PrimitiveType.Number:
                            try
                            {
                                // compare the values
                                // +0 and -0 are treated as "equal" in C#, so we don't need to test them separately.
                                // and NaN is always unequal to everything else, including itself.
                                if (left.IsOkayToCombine && right.IsOkayToCombine)
                                {
                                    newLiteral = new ConstantWrapper(left.ToNumber() != right.ToNumber(), PrimitiveType.Boolean, null, m_parser);
                                }
                            }
                            catch (InvalidCastException)
                            {
                                // some kind of casting in ToNumber caused a situation where we don't want
                                // to perform the combination on these operands
                            }
                            break;
                    }
                }
                else
                {
                    // if they aren't the same type, they are not equal
                    newLiteral = new ConstantWrapper(true, PrimitiveType.Boolean, null, m_parser);
                }
            }

            return newLiteral;
        }
        private ConstantWrapper Modulo(ConstantWrapper left, ConstantWrapper right)
        {
            ConstantWrapper newLiteral = null;

            if (left.IsOkayToCombine && right.IsOkayToCombine
                && m_parser.Settings.IsModificationAllowed(TreeModifications.EvaluateNumericExpressions))
            {
                try
                {
                    double leftValue = left.ToNumber();
                    double rightValue = right.ToNumber();
                    double result = leftValue % rightValue;

                    if (ConstantWrapper.NumberIsOkayToCombine(result))
                    {
                        newLiteral = new ConstantWrapper(result, PrimitiveType.Number, null, m_parser);
                    }
                    else
                    {
                        if (!left.IsNumericLiteral && ConstantWrapper.NumberIsOkayToCombine(leftValue))
                        {
                            left.Parent.ReplaceChild(left, new ConstantWrapper(leftValue, PrimitiveType.Number, left.Context, m_parser));
                        }
                        if (!right.IsNumericLiteral && ConstantWrapper.NumberIsOkayToCombine(rightValue))
                        {
                            right.Parent.ReplaceChild(right, new ConstantWrapper(rightValue, PrimitiveType.Number, right.Context, m_parser));
                        }
                    }
                }
                catch (InvalidCastException)
                {
                    // some kind of casting in ToNumber caused a situation where we don't want
                    // to perform the combination on these operands
                }
            }

            return newLiteral;
        }
        private ConstantWrapper GreaterThanOrEqual(ConstantWrapper left, ConstantWrapper right)
        {
            ConstantWrapper newLiteral = null;

            if (m_parser.Settings.IsModificationAllowed(TreeModifications.EvaluateNumericExpressions))
            {
                if (left.IsStringLiteral && right.IsStringLiteral)
                {
                    if (left.IsOkayToCombine && right.IsOkayToCombine)
                    {
                        // do a straight ordinal comparison of the strings
                        newLiteral = new ConstantWrapper(string.CompareOrdinal(left.ToString(), right.ToString()) >= 0, PrimitiveType.Boolean, null, m_parser);
                    }
                }
                else
                {
                    try
                    {
                        // either one or both are NOT a string -- numeric comparison
                        if (left.IsOkayToCombine && right.IsOkayToCombine)
                        {
                            newLiteral = new ConstantWrapper(left.ToNumber() >= right.ToNumber(), PrimitiveType.Boolean, null, m_parser);
                        }
                    }
                    catch (InvalidCastException)
                    {
                        // some kind of casting in ToNumber caused a situation where we don't want
                        // to perform the combination on these operands
                    }
                }
            }

            return newLiteral;
        }