public void Visit(JsConstantWrapper node)
        {
            if (node != null)
            {
                var symbol = StartSymbol(node);

                var isNoIn = m_noIn;
                m_noIn = false;

                switch (node.PrimitiveType)
                {
                    case JsPrimitiveType.Boolean:
                        Output(node.ToBoolean() ? "true" : "false");
                        break;

                    case JsPrimitiveType.Null:
                        Output("null");
                        break;

                    case JsPrimitiveType.Number:
                        if (node.Context == null || !node.Context.HasCode
                            || (!node.MayHaveIssues && m_settings.IsModificationAllowed(JsTreeModifications.MinifyNumericLiterals)))
                        {
                            // apply minification to the literal to get it as small as possible
                            Output(NormalizeNumber(node.ToNumber(), node.Context));
                        }
                        else
                        {
                            // context is not null but we don't want to minify numeric literals.
                            // just use the original literal from the context.
                            Output(node.Context.Code);
                        }
                        break;

                    case JsPrimitiveType.Other:
                        Output(node.Value.ToString());
                        break;

                    case JsPrimitiveType.String:
                        if (node.Context == null || !node.Context.HasCode)
                        {
                            // escape the string value because we don't have a raw context value
                            // to show anyways
                            Output(InlineSafeString(EscapeString(node.Value.ToString())));
                        }
                        else if (!m_settings.IsModificationAllowed(JsTreeModifications.MinifyStringLiterals))
                        {
                            // we don't want to modify the strings at all!
                            Output(node.Context.Code);
                        }
                        else if (node.MayHaveIssues
                            || (m_settings.AllowEmbeddedAspNetBlocks && node.StringContainsAspNetReplacement))
                        {
                            // we'd rather show the raw string, but make sure it's safe for inlining
                            Output(InlineSafeString(node.Context.Code));
                        }
                        else
                        {
                            // we'd rather show the escaped string
                            Output(InlineSafeString(EscapeString(node.Value.ToString())));
                        }

                        break;
                }

                MarkSegment(node, null, node.Context);
                SetContextOutputPosition(node.Context);
                m_startOfStatement = false;
                m_noIn = isNoIn;

                EndSymbol(symbol);
            }
        }
        private JsConstantWrapper StrictNotEqual(JsConstantWrapper left, JsConstantWrapper right)
        {
            JsConstantWrapper newLiteral = null;

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

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

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

                        case JsPrimitiveType.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 JsConstantWrapper(left.ToNumber() != right.ToNumber(), JsPrimitiveType.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 JsConstantWrapper(true, JsPrimitiveType.Boolean, null, m_parser);
                }
            }

            return newLiteral;
        }
        private JsConstantWrapper Divide(JsConstantWrapper left, JsConstantWrapper right)
        {
            JsConstantWrapper newLiteral = null;

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

                    if (JsConstantWrapper.NumberIsOkayToCombine(result))
                    {
                        newLiteral = new JsConstantWrapper(result, JsPrimitiveType.Number, null, m_parser);
                    }
                    else
                    {
                        if (!left.IsNumericLiteral && JsConstantWrapper.NumberIsOkayToCombine(leftValue))
                        {
                            left.Parent.ReplaceChild(left, new JsConstantWrapper(leftValue, JsPrimitiveType.Number, left.Context, m_parser));
                        }
                        if (!right.IsNumericLiteral && JsConstantWrapper.NumberIsOkayToCombine(rightValue))
                        {
                            right.Parent.ReplaceChild(right, new JsConstantWrapper(rightValue, JsPrimitiveType.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 JsConstantWrapper LessThanOrEqual(JsConstantWrapper left, JsConstantWrapper right)
        {
            JsConstantWrapper newLiteral = null;

            if (m_parser.Settings.IsModificationAllowed(JsTreeModifications.EvaluateNumericExpressions))
            {
                if (left.IsStringLiteral && right.IsStringLiteral)
                {
                    if (left.IsOkayToCombine && right.IsOkayToCombine)
                    {
                        // do a straight ordinal comparison of the strings
                        newLiteral = new JsConstantWrapper(string.CompareOrdinal(left.ToString(), right.ToString()) <= 0, JsPrimitiveType.Boolean, null, m_parser);
                    }
                }
                else
                {
                    try
                    {
                        // either one or both are NOT a string -- numeric comparison
                        if (left.IsOkayToCombine && right.IsOkayToCombine)
                        {
                            newLiteral = new JsConstantWrapper(left.ToNumber() <= right.ToNumber(), JsPrimitiveType.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;
        }