Ejemplo n.º 1
0
        internal override void AnalyzeNode()
        {
            // recurse first, then check to see if the unary is still needed
            base.AnalyzeNode();

            // if the operand is a numeric literal
            ConstantWrapper constantWrapper = Operand as ConstantWrapper;

            if (constantWrapper != null &&
                constantWrapper.IsNumericLiteral)
            {
                // get the value of the constant. We've already screened it for numeric, so
                // we don't have to worry about catching any errors
                double doubleValue = constantWrapper.ToNumber();

                // if this is a unary minus...
                if (OperatorToken == JSToken.Minus &&
                    Parser.Settings.IsModificationAllowed(TreeModifications.ApplyUnaryMinusToNumericLiteral))
                {
                    // negate the value
                    constantWrapper.Value = -doubleValue;

                    // replace us with the negated constant
                    if (Parent.ReplaceChild(this, constantWrapper))
                    {
                        // the context for the minus will include the number (its operand),
                        // but the constant will just be the number. Update the context on
                        // the constant to be a copy of the context on the operator
                        constantWrapper.Context = Context.Clone();
                        return;
                    }
                }
                else if (OperatorToken == JSToken.Plus &&
                         Parser.Settings.IsModificationAllowed(TreeModifications.RemoveUnaryPlusOnNumericLiteral))
                {
                    // +NEG is still negative, +POS is still positive, and +0 is still 0.
                    // so just get rid of the unary operator altogether
                    if (Parent.ReplaceChild(this, constantWrapper))
                    {
                        // the context for the unary will include the number (its operand),
                        // but the constant will just be the number. Update the context on
                        // the constant to be a copy of the context on the operator
                        constantWrapper.Context = Context.Clone();
                        return;
                    }
                }
            }
        }
Ejemplo n.º 2
0
        protected virtual void CreateLiteralShortcuts()
        {
            if (m_literalMap != null)
            {
                // get a reference to the first function scope in the chain
                // might be this, might be a parent
                FunctionScope    functionScope = null;
                ActivationObject scope         = this;
                while (scope != null && (functionScope = scope as FunctionScope) == null)
                {
                    scope = scope.Parent;
                }

                // if we didn't find a parent function scope, then don't do any combining
                // because the literals are globals
                if (functionScope != null)
                {
                    // for each value in our literal map
                    foreach (string constantString in m_literalMap.Keys)
                    {
                        LiteralReference literalReference = m_literalMap[constantString];

                        // if the child scope isn't null, then we don't reference the literal
                        // and only one of our child scopes does, so we don't want to add the
                        // shortcut here.
                        // OR if there are no constant wrappers left in the list, then we've already
                        // replaced them all and there's nothing left to do.
                        // BUT if the child scope is null, either we reference it, or more than
                        // one child references it. So if there are any constant wrappers in the list,
                        // then we want to add the shortcut and replace all the constants
                        if (literalReference.ChildScope == null && literalReference.ConstantWrapperList.Count > 0)
                        {
                            // AND we only want to do it if it will be worthwhile.
                            // (and a constant of length 1 is never worthwhile)
                            int constantLength = constantString.Length;
                            if (constantLength > 1)
                            {
                                int minCount = (constantLength + 7) / (constantLength - 1);
                                if (literalReference.Count > minCount)
                                {
                                    // create a special name that won't collide with any other variable names
                                    string specialName = string.Format(CultureInfo.InvariantCulture, "[literal:{0}]", ++s_literalCounter);

                                    // add a generated var statement at the top of the function block that
                                    // is equal to the literal value (just use the first constant wrapper as a model)
                                    ConstantWrapper modelConstant = literalReference.ConstantWrapperList[0];

                                    // by default we will use the value of the first instance as the generated variable's value
                                    object generatedValue = modelConstant.Value;

                                    // BUT....
                                    // if this is a numeric value, then we need to determine whether we should use a
                                    // positive or negative version of this value to minimize the number of minus operators in the results
                                    if (modelConstant.IsNumericLiteral)
                                    {
                                        // first we need to go through the existing references and count how many negative values there are
                                        var numberOfNegatives = 0;
                                        foreach (ConstantWrapper constantWrapper in literalReference.ConstantWrapperList)
                                        {
                                            // since the model us numeric, we shouldn't have any problems calling the
                                            // ToNumber method on the others (which should all also be numeric)
                                            if (constantWrapper.ToNumber() < 0)
                                            {
                                                ++numberOfNegatives;
                                            }
                                        }

                                        // now if more than half of the references are negative, we will want the generated value
                                        // to also be negative! Otherwise we want to force it to Positive.
                                        var absoluteValue = Math.Abs((double)generatedValue);
                                        if (numberOfNegatives > literalReference.ConstantWrapperList.Count / 2)
                                        {
                                            // force it to negative
                                            generatedValue = -absoluteValue;
                                        }
                                        else
                                        {
                                            // force it to positive
                                            generatedValue = absoluteValue;
                                        }
                                    }

                                    // add the generated variable to the function scope
                                    functionScope.FunctionObject.AddGeneratedVar(
                                        specialName,
                                        new ConstantWrapper(
                                            generatedValue,
                                            modelConstant.PrimitiveType,
                                            modelConstant.Context,
                                            Parser),
                                        true);

                                    // walk the list of constant wrappers backwards (because we'll be removing them
                                    // as we go along) and replace each one with a lookup for the generated variable.
                                    // Don't forget to analyze the lookup.
                                    for (int ndx = literalReference.ConstantWrapperList.Count - 1; ndx >= 0; --ndx)
                                    {
                                        ConstantWrapper constantWrapper = literalReference.ConstantWrapperList[ndx];

                                        // create the lookup based on the thisliteral context
                                        Lookup lookup = new Lookup(specialName, constantWrapper.Context, Parser);
                                        // indicate this is generated by our code, not the user
                                        lookup.IsGenerated = true;

                                        // by default, we're just going to replace the constant with the lookup
                                        AstNode replacement = lookup;

                                        // if the constant wrapper is a numeric value that is the NEGATIVE of the
                                        // combined numeric value (which would happen if the literal was subsequently
                                        // combined with a unary minus operator), then we need to change this to a unary-minus
                                        // operator on the lookup, not just the lookup.
                                        if (constantWrapper.IsNumericLiteral)
                                        {
                                            // since the constant wrapper is numeric, we shouldn't have any problems
                                            // calling ToNumber
                                            if ((double)generatedValue == -constantWrapper.ToNumber())
                                            {
                                                // it has been negated! Change the replacement to a unary minus operator
                                                // with the lookup as its operand
                                                replacement = new NumericUnary(
                                                    constantWrapper.Context,
                                                    Parser,
                                                    lookup,
                                                    JSToken.Minus);
                                            }
                                        }

                                        // replace the this literal with the appropriate node
                                        constantWrapper.Parent.ReplaceChild(constantWrapper, replacement);

                                        // set up the lookup's outer local field using the scope of the
                                        // original constant wrapper
                                        lookup.SetOuterLocalField(constantWrapper.EnclosingScope);

                                        // and remove it from the list. This is so child scopes don't also try to
                                        // add a shortcut -- the list will be empty.
                                        literalReference.ConstantWrapperList.RemoveAt(ndx);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
Ejemplo n.º 3
0
        public override void CleanupNodes()
        {
            base.CleanupNodes();

            if (Parser.Settings.EvalLiteralExpressions &&
                Parser.Settings.IsModificationAllowed(TreeModifications.EvaluateNumericExpressions))
            {
                // see if our operand is a ConstantWrapper
                ConstantWrapper literalOperand = Operand as ConstantWrapper;
                if (literalOperand != null)
                {
                    // must be number, boolean, string, or null
                    switch (OperatorToken)
                    {
                    case JSToken.Plus:
                        try
                        {
                            // replace with a constant representing operand.ToNumber,
                            Parent.ReplaceChild(this, new ConstantWrapper(literalOperand.ToNumber(), PrimitiveType.Number, Context, 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;

                    case JSToken.Minus:
                        try
                        {
                            // replace with a constant representing the negative of operand.ToNumber
                            Parent.ReplaceChild(this, new ConstantWrapper(-literalOperand.ToNumber(), PrimitiveType.Number, Context, 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;

                    case JSToken.BitwiseNot:
                        try
                        {
                            // replace with a constant representing the bitwise-not of operant.ToInt32
                            Parent.ReplaceChild(this, new ConstantWrapper(Convert.ToDouble(~literalOperand.ToInt32()), PrimitiveType.Number, Context, 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;

                    case JSToken.LogicalNot:
                        // replace with a constant representing the opposite of operand.ToBoolean
                        try
                        {
                            Parent.ReplaceChild(this, new ConstantWrapper(!literalOperand.ToBoolean(), PrimitiveType.Boolean, Context, Parser));
                        }
                        catch (InvalidCastException)
                        {
                            // ignore any invalid cast exceptions
                        }
                        break;
                    }
                }
            }
        }
Ejemplo n.º 4
0
        private ConstantWrapper Equal(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 true
                            newLiteral = new ConstantWrapper(true, 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
                            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 (left.IsOkayToCombine && right.IsOkayToCombine)
                {
                    try
                    {
                        // numeric comparison
                        // +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.
                        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;
        }
Ejemplo n.º 5
0
        private ConstantWrapper Divide(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;
        }
Ejemplo n.º 6
0
        private ConstantWrapper LessThanOrEqual(ConstantWrapper left, ConstantWrapper right)
        {
            ConstantWrapper newLiteral = null;

            if (m_parser.Settings.IsModificationAllowed(TreeModifications.EvaluateNumericExpressions))
            {
                if (left.IsStringLiteral && right.IsStringLiteral)
                {
                    // 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;
        }