public void Visit(ConstantWrapper node)
        {
            if (node != null)
            {
                // allow string, number, true, false, and null.
                switch (node.PrimitiveType)
                {
                case PrimitiveType.Boolean:
                    m_writer.Write((bool)node.Value ? "true" : "false");
                    break;

                case PrimitiveType.Null:
                    m_writer.Write("null");
                    break;

                case PrimitiveType.Number:
                    OutputNumber((double)node.Value, node.Context);
                    break;

                case PrimitiveType.String:
                case PrimitiveType.Other:
                    // string -- or treat it like a string
                    OutputString(node.Value.ToString());
                    break;
                }
            }
        }
Esempio n. 2
0
File: if.cs Progetto: formist/LinkMe
        public override void CleanupNodes()
        {
            base.CleanupNodes();

            if (Parser.Settings.EvalLiteralExpressions &&
                Parser.Settings.IsModificationAllowed(TreeModifications.EvaluateNumericExpressions))
            {
                // if the if-condition is a constant, we can eliminate one of the two branches
                ConstantWrapper constantCondition = Condition as ConstantWrapper;
                if (constantCondition != null)
                {
                    // instead, replace the condition with a 1 if it's always true or a 0 if it's always false
                    if (constantCondition.IsNotOneOrPositiveZero)
                    {
                        try
                        {
                            Condition = new ConstantWrapper(constantCondition.ToBoolean() ? 1 : 0, PrimitiveType.Number, null, Parser);
                        }
                        catch (InvalidCastException)
                        {
                            // ignore any invalid cast exceptions
                        }
                    }
                }
            }
        }
Esempio n. 3
0
        public override void CleanupNodes()
        {
            base.CleanupNodes();

            if (Parser.Settings.EvalLiteralExpressions &&
                Parser.Settings.IsModificationAllowed(TreeModifications.EvaluateNumericExpressions))
            {
                // if the condition is a literal, evaluating the condition doesn't do anything, AND
                // we know now whether it's true or not.
                ConstantWrapper literalCondition = m_condition as ConstantWrapper;
                if (literalCondition != null)
                {
                    try
                    {
                        // if the boolean represenation of the literal is true, we can replace the condition operator
                        // with the true expression; otherwise we can replace it with the false expression
                        Parent.ReplaceChild(this, literalCondition.ToBoolean() ? m_trueExpression : m_falseExpression);
                    }
                    catch (InvalidCastException)
                    {
                        // ignore any invalid cast errors
                    }
                }
            }
        }
Esempio n. 4
0
        public override void CleanupNodes()
        {
            base.CleanupNodes();

            if (Parser.Settings.EvalLiteralExpressions &&
                Parser.Settings.IsModificationAllowed(TreeModifications.EvaluateNumericExpressions))
            {
                ConstantWrapper constantCondition = Condition as ConstantWrapper;
                if (constantCondition != null)
                {
                    try
                    {
                        // if condition is always false, change it to a zero (only one byte)
                        // and if it is always true, remove it (default behavior)
                        if (constantCondition.ToBoolean())
                        {
                            // always true -- don't need a condition at all
                            Condition = null;
                        }
                        else if (constantCondition.IsNotOneOrPositiveZero)
                        {
                            // always false and it's not already a zero. Make it so (only one byte)
                            Condition = new ConstantWrapper(0, PrimitiveType.Number, null, Parser);
                        }
                    }
                    catch (InvalidCastException)
                    {
                        // ignore any invalid cast exceptions
                    }
                }
            }
        }
Esempio n. 5
0
 public void Visit(ConstantWrapper node)
 {
     if (node != null)
     {
         DoesRequire = true;
     }
 }
Esempio n. 6
0
 public void Visit(ConstantWrapper node)
 {
     // elisions in rrays are allowed, but don't recurse or contribute.
     // nothing else is allowed, though.
     if (node != null && node.Value != Missing.Value)
     {
         ReportError(node);
     }
 }
Esempio n. 7
0
            public override void Visit(CallNode node)
            {
                base.Visit(node);

                if (ShouldInsertModulePathArgument(node))
                {
                    var modulePathNode = new ConstantWrapper(modulePath, PrimitiveType.String, node.Context, node.Parser);
                    node.Arguments.Insert(0, modulePathNode);
                }
            }
        private bool IsMinificationHint(ConstantWrapper node)
        {
            var isHint = false;

            if (node.PrimitiveType == PrimitiveType.String)
            {
                // try splitting on commas and removing empty items
                var sections = node.ToString().Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                foreach (var section in sections)
                {
                    // valid hints are:
                    //      name:nomunge    don't automatically rename the field defined in this scope named "name"
                    //                      if name is missing (colon is the first character) or "*", then don't rename ANY
                    //                      fields defined in the current scope.
                    var ndxColon = section.IndexOf(':');
                    if (ndxColon >= 0)
                    {
                        // make sure this is a "nomunge" hint. If it is, then the entire node is treated as a hint and
                        // will be removed from the AST.
                        if (string.Compare(section.Substring(ndxColon + 1).Trim(), "nomunge", StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            // it is.
                            isHint = true;

                            // get the name that we don't want to munge. Null means all. Convert "*"
                            // to null.
                            var identifier = section.Substring(0, ndxColon).Trim();
                            if (string.IsNullOrEmpty(identifier) || string.CompareOrdinal(identifier, "*") == 0)
                            {
                                identifier = null;
                            }

                            // get the current scope and iterate over all the fields within it
                            // looking for just the ones that are defined here (outer is null)
                            var currentScope = node.EnclosingScope ?? m_globalScope;
                            foreach (var field in currentScope.NameTable.Values)
                            {
                                if (field.OuterField == null)
                                {
                                    // if the identifier is null or matches exactly, mark it as not crunchable
                                    if (identifier == null || string.CompareOrdinal(identifier, field.Name) == 0)
                                    {
                                        field.CanCrunch = false;
                                    }
                                }
                            }
                        }
                    }
                }
            }

            return(isHint);
        }
Esempio n. 9
0
 public bool IsSingleConstantArgument(string argumentValue)
 {
     if (m_list.Count == 1)
     {
         ConstantWrapper constantWrapper = m_list[0] as ConstantWrapper;
         if (constantWrapper != null &&
             string.CompareOrdinal(constantWrapper.Value.ToString(), argumentValue) == 0)
         {
             return(true);
         }
     }
     return(false);
 }
Esempio n. 10
0
            public LiteralReference(ConstantWrapper constantWrapper, ActivationObject childScope, List <ConstantWrapper> sharedList)
            {
                m_count      = 1;
                m_childScope = childScope;

                // use the shared list passed to us, or create a new one
                m_constantWrappers = sharedList ?? new List <ConstantWrapper>();

                // only add the constant wrapper passed to us IF it isn't ALREADY in the list
                // (will only happen with a shared list)
                if (!m_constantWrappers.Contains(constantWrapper))
                {
                    m_constantWrappers.Add(constantWrapper);
                }
            }
Esempio n. 11
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;
                    }
                }
            }
        }
Esempio n. 12
0
 public override void Visit(ConstantWrapper node)
 {
     if (node != null)
     {
         // no children, so don't bother calling the base.
         if (node.PrimitiveType == PrimitiveType.Boolean
             && m_parser.Settings.IsModificationAllowed(TreeModifications.BooleanLiteralsToNotOperators))
         {
             node.Parent.ReplaceChild(node, new NumericUnary(
                 node.Context,
                 m_parser,
                 new ConstantWrapper(node.ToBoolean() ? 0 : 1, PrimitiveType.Number, node.Context, m_parser),
                 JSToken.LogicalNot));
         }
     }
 }
Esempio n. 13
0
 internal override string GetFunctionGuess(AstNode target)
 {
     // MSN VOODOO: treat the as and ns methods as special if the expression is the root,
     // the parent is the call, and there is one string parameter -- use the string parameter
     if (Root == target && (Name == "as" || Name == "ns"))
     {
         CallNode call = Parent as CallNode;
         if (call != null && call.Arguments.Count == 1)
         {
             ConstantWrapper firstParam = call.Arguments[0] as ConstantWrapper;
             if (firstParam != null)
             {
                 return(firstParam.ToString());
             }
         }
     }
     return(Name);
 }
 public override void Visit(ConstantWrapper node)
 {
     // by default this node has nothing to do and no children to recurse.
     // but if this node's parent is a block, then this is an expression statement
     // consisting of a single string literal. Normally we would ignore these -- if
     // they occured at the top of the block they would be DirectivePrologues. So because
     // this exists, it must not be at the top. But we still want to check it for the nomunge
     // hints and respect them if that's what it is.
     if (node != null && node.Parent is Block)
     {
         // if this is a hint, process it as such.
         if (IsMinificationHint(node))
         {
             // and then remove it. We can do that here, because blocks are processed
             // in reverse order.
             node.Parent.ReplaceChild(node, null);
         }
     }
 }
        /// <summary>
        /// Optimized string literal concatenation for repeat usage pattern, avoiding multiple copying and allocation
        /// </summary>
        /// <param name="other"></param>
        /// <returns></returns>
        public StringList Concat(ConstantWrapper other)
        {
            var left = this.Value;

            if (this.PrimitiveType != PrimitiveType.String)
            {
                left = this.ToString();
            }

            object right = null;

            if (other != null)
            {
                right = other.Value;
                if (other.PrimitiveType != PrimitiveType.String)
                {
                    right = other.ToString();
                }
            }

            return(new StringList(left, right));
        }
Esempio n. 16
0
        internal override string GetFunctionGuess(AstNode target)
        {
            // get our guess from the function call
            string funcName = m_func.GetFunctionGuess(target);

            // MSN VOODOO: if this is the addMethod method, then the
            // name of the function is the first parameter.
            // The syntax of the add method call is: obj.addMethod("name",function(){...})
            // so there should be two parameters....
            if (funcName == "addMethod" && m_args.Count == 2)
            {
                // the first one should be a string constant....
                ConstantWrapper firstParam = m_args[0] as ConstantWrapper;
                // and the second one should be the function expression we're looking for
                if ((firstParam != null) && (firstParam.Value is string) && (m_args[1] == target))
                {
                    // use that first parameter as the guess
                    funcName = firstParam.ToString();
                }
            }
            return(funcName);
        }
Esempio n. 17
0
        public override void CleanupNodes()
        {
            base.CleanupNodes();

            if (Parser.Settings.EvalLiteralExpressions &&
                Parser.Settings.IsModificationAllowed(TreeModifications.EvaluateNumericExpressions))
            {
                // if the condition is a constant, we can simplify things
                ConstantWrapper constantCondition = Condition as ConstantWrapper;
                if (constantCondition != null && constantCondition.IsNotOneOrPositiveZero)
                {
                    try
                    {
                        // the condition is a constant, so it is always either true or false
                        // we can replace the condition with a one or a zero -- only one byte
                        Condition = new ConstantWrapper(constantCondition.ToBoolean() ? 1 : 0, PrimitiveType.Number, null, Parser);
                    }
                    catch (InvalidCastException)
                    {
                        // ignore any invalid cast errors
                    }
                }
            }
        }
Esempio n. 18
0
        /// <summary>
        /// Evaluate: (CONST [op] OTHER) [op] CONST
        /// </summary>
        /// <param name="thisConstant">second constant</param>
        /// <param name="otherConstant">first constant</param>
        /// <param name="leftOperator">first operator</param>
        private void EvalFarToTheLeft(BinaryOperator node, ConstantWrapper thisConstant, ConstantWrapper otherConstant, BinaryOperator leftOperator)
        {
            if (leftOperator.OperatorToken == JSToken.Minus)
            {
                if (node.OperatorToken == JSToken.Plus)
                {
                    // minus-plus
                    ConstantWrapper newLiteral = NumericAddition(otherConstant, thisConstant);
                    if (newLiteral != null && NoOverflow(newLiteral))
                    {
                        RotateFromRight(node, leftOperator, newLiteral);
                    }
                }
                else if (node.OperatorToken == JSToken.Minus)
                {
                    // minus-minus
                    ConstantWrapper newLiteral = Minus(otherConstant, thisConstant);
                    if (newLiteral != null && NoOverflow(newLiteral))
                    {
                        RotateFromRight(node, leftOperator, newLiteral);
                    }
                }
            }
            else if (node.OperatorToken == JSToken.Multiply)
            {
                if (leftOperator.OperatorToken == JSToken.Multiply || leftOperator.OperatorToken == JSToken.Divide)
                {
                    ConstantWrapper newLiteral = Multiply(otherConstant, thisConstant);
                    if (newLiteral != null && NoMultiplicativeOverOrUnderFlow(otherConstant, thisConstant, newLiteral))
                    {
                        RotateFromRight(node, leftOperator, newLiteral);
                    }
                }
            }
            else if (node.OperatorToken == JSToken.Divide)
            {
                if (leftOperator.OperatorToken == JSToken.Divide)
                {
                    // divide-divide
                    ConstantWrapper newLiteral = Divide(otherConstant, thisConstant);
                    if (newLiteral != null && NoMultiplicativeOverOrUnderFlow(otherConstant, thisConstant, newLiteral)
                        && newLiteral.ToCode().Length <= thisConstant.ToCode().Length + otherConstant.ToCode().Length + 1)
                    {
                        RotateFromRight(node, leftOperator, newLiteral);
                    }
                }
                else if (leftOperator.OperatorToken == JSToken.Multiply)
                {
                    // mult-divide
                    ConstantWrapper otherOverThis = Divide(otherConstant, thisConstant);
                    ConstantWrapper thisOverOther = Divide(thisConstant, otherConstant);

                    int otherOverThisLength = otherOverThis != null ? otherOverThis.ToCode().Length : int.MaxValue;
                    int thisOverOtherLength = thisOverOther != null ? thisOverOther.ToCode().Length : int.MaxValue;

                    if (otherOverThis != null && NoMultiplicativeOverOrUnderFlow(otherConstant, thisConstant, otherOverThis)
                        && (thisOverOther == null || otherOverThisLength < thisOverOtherLength))
                    {
                        if (otherOverThisLength <= thisConstant.ToCode().Length + otherConstant.ToCode().Length + 1)
                        {
                            RotateFromRight(node, leftOperator, otherOverThis);
                        }
                    }
                    else if (thisOverOther != null && NoMultiplicativeOverOrUnderFlow(thisConstant, otherConstant, thisOverOther))
                    {
                        if (thisOverOtherLength <= thisConstant.ToCode().Length + otherConstant.ToCode().Length + 1)
                        {
                            // swap the operands
                            leftOperator.SwapOperands();

                            // operator is the opposite
                            leftOperator.OperatorToken = JSToken.Divide;
                            RotateFromLeft(node, leftOperator, thisOverOther);
                        }
                    }
                }
            }
        }
Esempio n. 19
0
        internal override void AnalyzeNode()
        {
            // if we don't even have any resource strings, then there's nothing
            // we need to do and we can just perform the base operation
            ResourceStrings resourceStrings = Parser.ResourceStrings;

            if (resourceStrings != null && resourceStrings.Count > 0)
            {
                // see if the root object is a lookup that corresponds to the
                // global value (not a local field) for our resource object
                // (same name)
                Lookup rootLookup = Root as Lookup;
                if (rootLookup != null &&
                    rootLookup.LocalField == null &&
                    string.CompareOrdinal(rootLookup.Name, resourceStrings.Name) == 0)
                {
                    // it is -- we're going to replace this with a string value.
                    // if this member name is a string on the object, we'll replacve it with
                    // the literal. Otherwise we'll replace it with an empty string.
                    // see if the string resource contains this value
                    ConstantWrapper stringLiteral = new ConstantWrapper(
                        resourceStrings[Name],
                        PrimitiveType.String,
                        Context,
                        Parser
                        );

                    Parent.ReplaceChild(this, stringLiteral);
                    // analyze the literal
                    stringLiteral.AnalyzeNode();
                    return;
                }
            }

            // if we are replacing property names and we have something to replace
            if (Parser.Settings.HasRenamePairs && Parser.Settings.ManualRenamesProperties &&
                Parser.Settings.IsModificationAllowed(TreeModifications.PropertyRenaming))
            {
                // see if this name is a target for replacement
                string newName = Parser.Settings.GetNewName(Name);
                if (!string.IsNullOrEmpty(newName))
                {
                    // it is -- set the name to the new name
                    Name = newName;
                }
            }

            // recurse
            base.AnalyzeNode();

            /* REVIEW: might be too late in the parsing -- references to the variable may have
             * already been analyzed and found undefined
             * // see if we are assigning to a member on the global window object
             * BinaryOperator binaryOp = Parent as BinaryOperator;
             * if (binaryOp != null && binaryOp.IsAssign && m_rootObject.IsWindowLookup)
             * {
             *  // make sure the name of this property is a valid global variable, since we
             *  // are now assigning to it.
             *  if (Parser.GlobalScope[Name] == null)
             *  {
             *      // it's not -- we need to add it to our list of known globals
             *      // by defining a global field for it
             *      Parser.GlobalScope.DeclareField(Name, null, 0);
             *  }
             * }
             */
        }
Esempio n. 20
0
        //---------------------------------------------------------------------------------------
        // ParseLeftHandSideExpression
        //
        //  LeftHandSideExpression :
        //    PrimaryExpression Accessor  |
        //    'new' LeftHandSideExpression |
        //    FunctionExpression
        //
        //  PrimaryExpression :
        //    'this' |
        //    Identifier |
        //    Literal |
        //    '(' Expression ')'
        //
        //  FunctionExpression :
        //    'function' OptionalFuncName '(' FormalParameterList ')' { FunctionBody }
        //
        //  OptionalFuncName :
        //    <empty> |
        //    Identifier
        //---------------------------------------------------------------------------------------
        private AstNode ParseLeftHandSideExpression(bool isMinus)
        {
            AstNode ast = null;
            bool isFunction = false;
            List<Context> newContexts = null;

            TryItAgain:

            // new expression
            while (JSToken.New == m_currentToken.Token)
            {
                if (null == newContexts)
                    newContexts = new List<Context>(4);
                newContexts.Add(m_currentToken.Clone());
                GetNextToken();
            }
            JSToken token = m_currentToken.Token;
            switch (token)
            {
                // primary expression
                case JSToken.Identifier:
                    ast = new Lookup(m_scanner.GetIdentifier(), m_currentToken.Clone(), this);
                    break;

                case JSToken.ConditionalCommentStart:
                    // skip past the start to the next token
                    GetNextToken();
                    if (m_currentToken.Token == JSToken.PreprocessorConstant)
                    {
                        // we have /*@id
                        ast = new ConstantWrapperPP(m_currentToken.Code, true, m_currentToken.Clone(), this);
                        GetNextToken();

                        if (m_currentToken.Token == JSToken.ConditionalCommentEnd)
                        {
                            // skip past the closing comment
                            GetNextToken();
                        }
                        else
                        {
                            // we ONLY support /*@id@*/ in expressions right now. If there's not
                            // a closing comment after the ID, then we don't support it.
                            // throw an error, skip to the end of the comment, then ignore it and start
                            // looking for the next token.
                            m_currentToken.HandleError(JSError.ConditionalCompilationTooComplex);

                            // skip to end of conditional comment
                            while (m_currentToken.Token != JSToken.EndOfFile && m_currentToken.Token != JSToken.ConditionalCommentEnd)
                            {
                                GetNextToken();
                            }
                            GetNextToken();
                            goto TryItAgain;
                        }
                    }
                    else if (m_currentToken.Token == JSToken.ConditionalCommentEnd)
                    {
                        // empty conditional comment! Ignore.
                        GetNextToken();
                        goto TryItAgain;
                    }
                    else
                    {
                        // we DON'T have "/*@IDENT". We only support "/*@IDENT @*/", so since this isn't
                        // and id, throw the error, skip to the end of the comment, and ignore it
                        // by looping back and looking for the NEXT token.
                        m_currentToken.HandleError(JSError.ConditionalCompilationTooComplex);

                        // skip to end of conditional comment
                        while (m_currentToken.Token != JSToken.EndOfFile && m_currentToken.Token != JSToken.ConditionalCommentEnd)
                        {
                            GetNextToken();
                        }
                        GetNextToken();
                        goto TryItAgain;
                    }
                    break;

                case JSToken.This:
                    ast = new ThisLiteral(m_currentToken.Clone(), this);
                    break;

                case JSToken.StringLiteral:
                    ast = new ConstantWrapper(m_scanner.StringLiteral, PrimitiveType.String, m_currentToken.Clone(), this);
                    break;

                case JSToken.IntegerLiteral:
                case JSToken.NumericLiteral:
                    {
                        Context numericContext = m_currentToken.Clone();
                        double doubleValue;
                        if (ConvertNumericLiteralToDouble(m_currentToken.Code, (token == JSToken.IntegerLiteral), out doubleValue))
                        {
                            // conversion worked fine
                            // check for some boundary conditions
                            if (doubleValue == double.MaxValue)
                            {
                                ReportError(JSError.NumericMaximum, numericContext, true);
                            }
                            else if (isMinus && -doubleValue == double.MinValue)
                            {
                                ReportError(JSError.NumericMinimum, numericContext, true);
                            }

                            // create the constant wrapper from the value
                            ast = new ConstantWrapper(doubleValue, PrimitiveType.Number, numericContext, this);
                        }
                        else
                        {
                            // check to see if we went overflow
                            if (double.IsInfinity(doubleValue))
                            {
                                ReportError(JSError.NumericOverflow, numericContext, true);
                            }

                            // regardless, we're going to create a special constant wrapper
                            // that simply echos the input as-is
                            ast = new ConstantWrapper(m_currentToken.Code, PrimitiveType.Other, numericContext, this);
                        }
                        break;
                    }

                case JSToken.True:
                    ast = new ConstantWrapper(true, PrimitiveType.Boolean, m_currentToken.Clone(), this);
                    break;

                case JSToken.False:
                    ast = new ConstantWrapper(false, PrimitiveType.Boolean, m_currentToken.Clone(), this);
                    break;

                case JSToken.Null:
                    ast = new ConstantWrapper(null, PrimitiveType.Null, m_currentToken.Clone(), this);
                    break;

                case JSToken.PreprocessorConstant:
                    ast = new ConstantWrapperPP(m_currentToken.Code, false, m_currentToken.Clone(), this);
                    break;

                case JSToken.DivideAssign:
                // normally this token is not allowed on the left-hand side of an expression.
                // BUT, this might be the start of a regular expression that begins with an equals sign!
                // we need to test to see if we can parse a regular expression, and if not, THEN
                // we can fail the parse.

                case JSToken.Divide:
                    // could it be a regexp?
                    String source = m_scanner.ScanRegExp();
                    if (source != null)
                    {
                        // parse the flags (if any)
                        String flags = m_scanner.ScanRegExpFlags();
                        // create the literal
                        ast = new RegExpLiteral(source, flags, m_currentToken.Clone(), this);
                        break;
                    }
                    goto default;

                // expression
                case JSToken.LeftParenthesis:
                    {
                        // save the current context reference
                        Context openParenContext = m_currentToken.Clone();
                        GetNextToken();
                        m_noSkipTokenSet.Add(NoSkipTokenSet.s_ParenExpressionNoSkipToken);
                        try
                        {
                            // parse an expression
                            ast = ParseExpression();
                            
                            // update the expression's context with the context of the open paren
                            ast.Context.UpdateWith(openParenContext);
                            if (JSToken.RightParenthesis != m_currentToken.Token)
                            {
                                ReportError(JSError.NoRightParenthesis);
                            }
                            else
                            {
                                // add the closing paren to the expression context
                                ast.Context.UpdateWith(m_currentToken);
                            }
                        }
                        catch (RecoveryTokenException exc)
                        {
                            if (IndexOfToken(NoSkipTokenSet.s_ParenExpressionNoSkipToken, exc) == -1)
                                throw;
                            else
                                ast = exc._partiallyComputedNode;
                        }
                        finally
                        {
                            m_noSkipTokenSet.Remove(NoSkipTokenSet.s_ParenExpressionNoSkipToken);
                        }
                        if (ast == null) //this can only happen when catching the exception and nothing was sent up by the caller
                            SkipTokensAndThrow();
                    }
                    break;

                // array initializer
                case JSToken.LeftBracket:
                    Context listCtx = m_currentToken.Clone();
                    AstNodeList list = new AstNodeList(m_currentToken.Clone(), this);
                    GetNextToken();
                    while (JSToken.RightBracket != m_currentToken.Token)
                    {
                        if (JSToken.Comma != m_currentToken.Token)
                        {
                            m_noSkipTokenSet.Add(NoSkipTokenSet.s_ArrayInitNoSkipTokenSet);
                            try
                            {
                                list.Append(ParseExpression(true));
                                if (JSToken.Comma != m_currentToken.Token)
                                {
                                    if (JSToken.RightBracket != m_currentToken.Token)
                                        ReportError(JSError.NoRightBracket);
                                    break;
                                }
                                else
                                {
                                    // we have a comma -- skip it
                                    GetNextToken();

                                    // if the next token is the closing brackets, then we need to
                                    // add a missing value to the array because we end in a comma and
                                    // we need to keep it for cross-platform compat.
                                    // TECHNICALLY, that puts an extra item into the array for most modern browsers, but not ALL.
                                    if (m_currentToken.Token == JSToken.RightBracket)
                                    {
                                        list.Append(new ConstantWrapper(Missing.Value, PrimitiveType.Other, m_currentToken.Clone(), this));
                                    }
                                }
                            }
                            catch (RecoveryTokenException exc)
                            {
                                if (exc._partiallyComputedNode != null)
                                    list.Append(exc._partiallyComputedNode);
                                if (IndexOfToken(NoSkipTokenSet.s_ArrayInitNoSkipTokenSet, exc) == -1)
                                {
                                    listCtx.UpdateWith(CurrentPositionContext());
                                    exc._partiallyComputedNode = new ArrayLiteral(listCtx, this, list);
                                    throw;
                                }
                                else
                                {
                                    if (JSToken.RightBracket == m_currentToken.Token)
                                        break;
                                }
                            }
                            finally
                            {
                                m_noSkipTokenSet.Remove(NoSkipTokenSet.s_ArrayInitNoSkipTokenSet);
                            }
                        }
                        else
                        {
                            // comma -- missing array item in the list
                            list.Append(new ConstantWrapper(Missing.Value, PrimitiveType.Other, m_currentToken.Clone(), this));

                            // skip over the comma
                            GetNextToken();

                            // if the next token is the closing brace, then we end with a comma -- and we need to
                            // add ANOTHER missing value to make sure this last comma doesn't get left off.
                            // TECHNICALLY, that puts an extra item into the array for most modern browsers, but not ALL.
                            if (m_currentToken.Token == JSToken.RightBracket)
                            {
                                list.Append(new ConstantWrapper(Missing.Value, PrimitiveType.Other, m_currentToken.Clone(), this));
                            }
                        }
                    }
                    listCtx.UpdateWith(m_currentToken);
                    ast = new ArrayLiteral(listCtx, this, list);
                    break;

                // object initializer
                case JSToken.LeftCurly:
                    Context objCtx = m_currentToken.Clone();
                    GetNextToken();

                    // we're going to keep the keys and values in separate lists, but make sure
                    // that the indexes correlate (keyList[n] is associated with valueList[n])
                    List<ObjectLiteralField> keyList = new List<ObjectLiteralField>();
                    List<AstNode> valueList = new List<AstNode>();

                    if (JSToken.RightCurly != m_currentToken.Token)
                    {
                        for (; ; )
                        {
                            ObjectLiteralField field = null;
                            AstNode value = null;
                            bool getterSetter = false;
                            string ident;

                            switch (m_currentToken.Token)
                            {
                                case JSToken.Identifier:
                                    field = new ObjectLiteralField(m_scanner.GetIdentifier(), PrimitiveType.String, m_currentToken.Clone(), this);
                                    break;

                                case JSToken.StringLiteral:
                                    field = new ObjectLiteralField(m_scanner.StringLiteral, PrimitiveType.String, m_currentToken.Clone(), this);
                                    break;

                                case JSToken.IntegerLiteral:
                                case JSToken.NumericLiteral:
                                    {
                                        double doubleValue;
                                        if (ConvertNumericLiteralToDouble(m_currentToken.Code, (m_currentToken.Token == JSToken.IntegerLiteral), out doubleValue))
                                        {
                                            // conversion worked fine
                                            field = new ObjectLiteralField(
                                              doubleValue,
                                              PrimitiveType.Number,
                                              m_currentToken.Clone(),
                                              this
                                              );
                                        }
                                        else
                                        {
                                            // something went wrong and we're not sure the string representation in the source is 
                                            // going to convert to a numeric value well
                                            if (double.IsInfinity(doubleValue))
                                            {
                                                ReportError(JSError.NumericOverflow, m_currentToken.Clone(), true);
                                            }

                                            // use the source as the field name, not the numeric value
                                            field = new ObjectLiteralField(
                                                m_currentToken.Code,
                                                PrimitiveType.Other,
                                                m_currentToken.Clone(),
                                                this);
                                        }
                                        break;
                                    }

                                case JSToken.Get:
                                case JSToken.Set:
                                    if (m_scanner.PeekToken() == JSToken.Colon)
                                    {
                                        // the field is either "get" or "set" and isn't the special Mozilla getter/setter
                                        field = new ObjectLiteralField(m_currentToken.Code, PrimitiveType.String, m_currentToken.Clone(), this);
                                    }
                                    else
                                    {
                                        // ecma-script get/set property construct
                                        getterSetter = true;
                                        bool isGet = (m_currentToken.Token == JSToken.Get);
                                        value = ParseFunction(
                                          (JSToken.Get == m_currentToken.Token ? FunctionType.Getter : FunctionType.Setter),
                                          m_currentToken.Clone()
                                          );
                                        FunctionObject funcExpr = value as FunctionObject;
                                        if (funcExpr != null)
                                        {
                                            // getter/setter is just the literal name with a get/set flag
                                            field = new GetterSetter(
                                              funcExpr.Name,
                                              isGet,
                                              funcExpr.IdContext.Clone(),
                                              this
                                              );
                                        }
                                        else
                                        {
                                            ReportError(JSError.FunctionExpressionExpected);
                                        }
                                    }
                                    break;

                                default:
                                    // NOT: identifier, string, number, or getter/setter.
                                    // see if it's a token that COULD be an identifier.
                                    ident = JSKeyword.CanBeIdentifier(m_currentToken.Token);
                                    if (ident != null)
                                    {
                                        // don't throw a warning -- it's okay to have a keyword that
                                        // can be an identifier here.
                                        field = new ObjectLiteralField(ident, PrimitiveType.String, m_currentToken.Clone(), this);
                                    }
                                    else
                                    {
                                        ReportError(JSError.NoMemberIdentifier);
                                        field = new ObjectLiteralField("_#Missing_Field#_" + s_cDummyName++, PrimitiveType.String, CurrentPositionContext(), this);
                                    }
                                    break;
                            }

                            if (field != null)
                            {
                                if (!getterSetter)
                                {
                                    GetNextToken();
                                }

                                m_noSkipTokenSet.Add(NoSkipTokenSet.s_ObjectInitNoSkipTokenSet);
                                try
                                {
                                    if (!getterSetter)
                                    {
                                        // get the value
                                        if (JSToken.Colon != m_currentToken.Token)
                                        {
                                            ReportError(JSError.NoColon, true);
                                            value = ParseExpression(true);
                                        }
                                        else
                                        {
                                            GetNextToken();
                                            value = ParseExpression(true);
                                        }
                                    }

                                    // put the pair into the list of fields
                                    keyList.Add(field);
                                    valueList.Add(value);

                                    if (JSToken.RightCurly == m_currentToken.Token)
                                        break;
                                    else
                                    {
                                        if (JSToken.Comma == m_currentToken.Token)
                                        {
                                            // skip the comma
                                            GetNextToken();

                                            // if the next token is the right-curly brace, then we ended 
                                            // the list with a comma, which is perfectly fine
                                            if (m_currentToken.Token == JSToken.RightCurly)
                                            {
                                                break;
                                            }
                                        }
                                        else
                                        {
                                            if (m_scanner.GotEndOfLine)
                                            {
                                                ReportError(JSError.NoRightCurly);
                                            }
                                            else
                                                ReportError(JSError.NoComma, true);
                                            SkipTokensAndThrow();
                                        }
                                    }
                                }
                                catch (RecoveryTokenException exc)
                                {
                                    if (exc._partiallyComputedNode != null)
                                    {
                                        // the problem was in ParseExpression trying to determine value
                                        value = exc._partiallyComputedNode;
                                        keyList.Add(field);
                                        valueList.Add(value);
                                    }
                                    if (IndexOfToken(NoSkipTokenSet.s_ObjectInitNoSkipTokenSet, exc) == -1)
                                    {
                                        exc._partiallyComputedNode = new ObjectLiteral(objCtx, this, keyList.ToArray(), valueList.ToArray());
                                        throw;
                                    }
                                    else
                                    {
                                        if (JSToken.Comma == m_currentToken.Token)
                                            GetNextToken();
                                        if (JSToken.RightCurly == m_currentToken.Token)
                                            break;
                                    }
                                }
                                finally
                                {
                                    m_noSkipTokenSet.Remove(NoSkipTokenSet.s_ObjectInitNoSkipTokenSet);
                                }
                            }
                        }
                    }
                    objCtx.UpdateWith(m_currentToken);
                    ast = new ObjectLiteral(objCtx, this, keyList.ToArray(), valueList.ToArray());
                    break;

                // function expression
                case JSToken.Function:
                    ast = ParseFunction(FunctionType.Expression, m_currentToken.Clone());
                    isFunction = true;
                    break;

                case JSToken.AspNetBlock:
                    ast = ParseAspNetBlock(consumeSemicolonIfPossible: false);
                    break;

                default:
                    string identifier = JSKeyword.CanBeIdentifier(m_currentToken.Token);
                    if (null != identifier)
                    {
                        ast = new Lookup(identifier, m_currentToken.Clone(), this);
                    }
                    else
                    {
                        ReportError(JSError.ExpressionExpected);
                        SkipTokensAndThrow();
                    }
                    break;
            }

            // can be a CallExpression, that is, followed by '.' or '(' or '['
            if (!isFunction)
                GetNextToken();

            return MemberExpression(ast, newContexts);
        }
Esempio n. 21
0
        //---------------------------------------------------------------------------------------
        // ParseWithStatement
        //
        //  WithStatement :
        //    'with' '(' Expression ')' Statement
        //---------------------------------------------------------------------------------------
        private WithNode ParseWithStatement()
        {
            Context withCtx = m_currentToken.Clone();
            AstNode obj = null;
            Block block = null;
            m_blockType.Add(BlockType.Block);
            try
            {
                GetNextToken();
                if (JSToken.LeftParenthesis != m_currentToken.Token)
                    ReportError(JSError.NoLeftParenthesis);
                GetNextToken();
                m_noSkipTokenSet.Add(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet);
                try
                {
                    obj = ParseExpression();
                    if (JSToken.RightParenthesis != m_currentToken.Token)
                    {
                        withCtx.UpdateWith(obj.Context);
                        ReportError(JSError.NoRightParenthesis);
                    }
                    else
                        withCtx.UpdateWith(m_currentToken);
                    GetNextToken();
                }
                catch (RecoveryTokenException exc)
                {
                    if (IndexOfToken(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet, exc) == -1)
                    {
                        // give up
                        exc._partiallyComputedNode = null;
                        throw;
                    }
                    else
                    {
                        if (exc._partiallyComputedNode == null)
                            obj = new ConstantWrapper(true, PrimitiveType.Boolean, CurrentPositionContext(), this);
                        else
                            obj = exc._partiallyComputedNode;
                        withCtx.UpdateWith(obj.Context);

                        if (exc._token == JSToken.RightParenthesis)
                            GetNextToken();
                    }
                }
                finally
                {
                    m_noSkipTokenSet.Remove(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet);
                }

                // if the statements aren't withing curly-braces, throw a possible error
                if (JSToken.LeftCurly != m_currentToken.Token)
                {
                    ReportError(JSError.StatementBlockExpected, withCtx, true);
                }

                WithScope withScope = new WithScope(ScopeStack.Peek(), withCtx, this);
                ScopeStack.Push(withScope);
                try
                {
                    // parse a Statement, not a SourceElement
                    AstNode statement = ParseStatement(false);

                    // but make sure we save it as a block
                    block = statement as Block;
                    if (block == null)
                    {
                        block = new Block(statement.Context, this);
                        block.Append(statement);
                    }
                }
                catch (RecoveryTokenException exc)
                {
                    if (exc._partiallyComputedNode == null)
                    {
                        block = new Block(CurrentPositionContext(), this);
                    }
                    else
                    {
                        block = exc._partiallyComputedNode as Block;
                        if (block == null)
                        {
                            block = new Block(exc._partiallyComputedNode.Context, this);
                            block.Append(exc._partiallyComputedNode);
                        }
                    }
                    block.BlockScope = withScope;
                    exc._partiallyComputedNode = new WithNode(withCtx, this, obj, block);
                    throw;
                }
                finally
                {
                    // pop off the with-scope
                    ScopeStack.Pop();

                    // save the with-scope on the block
                    block.BlockScope = withScope;
                }
            }
            finally
            {
                m_blockType.RemoveAt(m_blockType.Count - 1);
            }

            return new WithNode(withCtx, this, obj, block);
        }
Esempio n. 22
0
        //---------------------------------------------------------------------------------------
        // ParseDoStatement
        //
        //  DoStatement:
        //    'do' Statement 'while' '(' Expression ')'
        //---------------------------------------------------------------------------------------
        private DoWhile ParseDoStatement()
        {
            Context doCtx = null;
            AstNode body = null;
            AstNode condition = null;
            m_blockType.Add(BlockType.Loop);
            try
            {
                GetNextToken();
                m_noSkipTokenSet.Add(NoSkipTokenSet.s_DoWhileBodyNoSkipTokenSet);
                // if the statements aren't withing curly-braces, throw a possible error
                if (JSToken.LeftCurly != m_currentToken.Token)
                {
                    ReportError(JSError.StatementBlockExpected, m_currentToken.Clone(), true);
                }
                try
                {
                    // parse a Statement, not a SourceElement
                    body = ParseStatement(false);
                }
                catch (RecoveryTokenException exc)
                {
                    // make up a block for the do while
                    if (exc._partiallyComputedNode != null)
                        body = exc._partiallyComputedNode;
                    else
                        body = new Block(CurrentPositionContext(), this);
                    if (IndexOfToken(NoSkipTokenSet.s_DoWhileBodyNoSkipTokenSet, exc) == -1)
                    {
                        // we have to pass the exception to someone else, make as much as you can from the 'do while'
                        exc._partiallyComputedNode = new DoWhile(CurrentPositionContext(), this,
                                                                  body,
                                                                  new ConstantWrapper(false, PrimitiveType.Boolean, CurrentPositionContext(), this));
                        throw;
                    }
                }
                finally
                {
                    m_noSkipTokenSet.Remove(NoSkipTokenSet.s_DoWhileBodyNoSkipTokenSet);
                }
                if (JSToken.While != m_currentToken.Token)
                {
                    ReportError(JSError.NoWhile);
                }
                doCtx = m_currentToken.Clone();
                GetNextToken();
                if (JSToken.LeftParenthesis != m_currentToken.Token)
                {
                    ReportError(JSError.NoLeftParenthesis);
                }
                GetNextToken();
                // catch here so the body of the do_while is not thrown away
                m_noSkipTokenSet.Add(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet);
                try
                {
                    condition = ParseExpression();
                    if (JSToken.RightParenthesis != m_currentToken.Token)
                    {
                        ReportError(JSError.NoRightParenthesis);
                        doCtx.UpdateWith(condition.Context);
                    }
                    else
                        doCtx.UpdateWith(m_currentToken);
                    GetNextToken();
                }
                catch (RecoveryTokenException exc)
                {
                    // make up a condition
                    if (exc._partiallyComputedNode != null)
                        condition = exc._partiallyComputedNode;
                    else
                        condition = new ConstantWrapper(false, PrimitiveType.Boolean, CurrentPositionContext(), this);

                    if (IndexOfToken(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet, exc) == -1)
                    {
                        exc._partiallyComputedNode = new DoWhile(doCtx, this, body, condition);
                        throw;
                    }
                    else
                    {
                        if (JSToken.RightParenthesis == m_currentToken.Token)
                            GetNextToken();
                    }
                }
                finally
                {
                    m_noSkipTokenSet.Remove(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet);
                }
                if (JSToken.Semicolon == m_currentToken.Token)
                {
                    // JScript 5 allowed statements like
                    //   do{print(++x)}while(x<10) print(0)
                    // even though that does not strictly follow the automatic semicolon insertion
                    // rules for the required semi after the while().  For backwards compatibility
                    // we should continue to support this.
                    doCtx.UpdateWith(m_currentToken);
                    GetNextToken();
                }

            }
            finally
            {
                m_blockType.RemoveAt(m_blockType.Count - 1);
            }

            return new DoWhile(doCtx, this, body, condition);
        }
 public void Visit(ConstantWrapper node)
 {
     // we're good
 }
Esempio n. 24
0
        private ConstantWrapper UnsignedRightShift(ConstantWrapper left, ConstantWrapper right)
        {
            ConstantWrapper newLiteral = null;

            if (m_parser.Settings.IsModificationAllowed(TreeModifications.EvaluateNumericExpressions))
            {
                try
                {
                    // left-hand value is a 32-bit signed integer
                    UInt32 lvalue = left.ToUInt32();

                    // mask only the bottom 5 bits of the right-hand value
                    int rvalue = (int)(right.ToUInt32() & 0x1F);

                    // convert the result to a double
                    double result = Convert.ToDouble(lvalue >> rvalue);
                    newLiteral = new ConstantWrapper(result, PrimitiveType.Number, 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;
        }
Esempio n. 25
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;
                    }
                }
            }
        }
Esempio n. 26
0
        /// <summary>
        /// Return true is not an overflow or underflow, for multiplication operations
        /// </summary>
        /// <param name="left">left operand</param>
        /// <param name="right">right operand</param>
        /// <param name="result">result</param>
        /// <returns>true if result not overflow or underflow; false if it is</returns>
        private static bool NoMultiplicativeOverOrUnderFlow(ConstantWrapper left, ConstantWrapper right, ConstantWrapper result)
        {
            // check for overflow
            bool okayToProceed = !result.IsInfinity;

            // if we still might be good, check for possible underflow
            if (okayToProceed)
            {
                // if the result is zero, we might have an underflow. But if one of the operands
                // was zero, then it's okay.
                // Inverse: if neither operand is zero, then a zero result is not okay
                okayToProceed = !result.IsZero || (left.IsZero || right.IsZero);
            }
            return okayToProceed;
        }
Esempio n. 27
0
 // the global scope does nothing when told to add literals -- just returns null
 internal override List <ConstantWrapper> AddLiteral(ConstantWrapper constantWrapper, ActivationObject refScope)
 {
     return(null);
 }
Esempio n. 28
0
 /// <summary>
 /// Return true if the result isn't an overflow condition
 /// </summary>
 /// <param name="result">result constant</param>
 /// <returns>true is not an overflow; false if it is</returns>
 private static bool NoOverflow(ConstantWrapper result)
 {
     return !result.IsInfinity;
 }
Esempio n. 29
0
        /// <summary>
        /// Eval the two constants: CONST [op] (OTHER [op] CONST)
        /// </summary>
        /// <param name="thisConstant">first constant</param>
        /// <param name="otherConstant">second constant</param>
        /// <param name="rightOperator">second operator</param>
        private void EvalFarToTheRight(BinaryOperator node, ConstantWrapper thisConstant, ConstantWrapper otherConstant, BinaryOperator rightOperator)
        {
            if (rightOperator.OperatorToken == JSToken.Minus)
            {
                if (node.OperatorToken == JSToken.Plus)
                {
                    // plus-minus
                    // our constant cannot be a string, though
                    if (!thisConstant.IsStringLiteral)
                    {
                        ConstantWrapper newLiteral = Minus(otherConstant, thisConstant);
                        if (newLiteral != null && NoOverflow(newLiteral))
                        {
                            RotateFromLeft(node, rightOperator, newLiteral);
                        }
                    }
                }
                else if (node.OperatorToken == JSToken.Minus)
                {
                    // minus-minus
                    ConstantWrapper newLiteral = NumericAddition(thisConstant, otherConstant);
                    if (newLiteral != null && NoOverflow(newLiteral))
                    {
                        // but we need to swap the left and right operands first
                        rightOperator.SwapOperands();

                        // then rotate the node up after replacing old with new
                        RotateFromRight(node, rightOperator, newLiteral);
                    }
                }
            }
            else if (node.OperatorToken == JSToken.Multiply)
            {
                if (rightOperator.OperatorToken == JSToken.Multiply)
                {
                    // mult-mult
                    ConstantWrapper newLiteral = Multiply(thisConstant, otherConstant);
                    if (newLiteral != null && NoMultiplicativeOverOrUnderFlow(thisConstant, otherConstant, newLiteral))
                    {
                        RotateFromLeft(node, rightOperator, newLiteral);
                    }
                }
                else if (rightOperator.OperatorToken == JSToken.Divide)
                {
                    // mult-divide
                    ConstantWrapper otherOverThis = Divide(otherConstant, thisConstant);
                    ConstantWrapper thisOverOther = Divide(thisConstant, otherConstant);

                    int otherOverThisLength = otherOverThis != null ? otherOverThis.ToCode().Length : int.MaxValue;
                    int thisOverOtherLength = thisOverOther != null ? thisOverOther.ToCode().Length : int.MaxValue;

                    if (otherOverThis != null && NoMultiplicativeOverOrUnderFlow(otherConstant, thisConstant, otherOverThis)
                        && (thisOverOther == null || otherOverThisLength < thisOverOtherLength))
                    {
                        if (otherOverThisLength <= thisConstant.ToCode().Length + otherConstant.ToCode().Length + 1)
                        {
                            // swap the operands, but keep the operator
                            RotateFromLeft(node, rightOperator, otherOverThis);
                        }
                    }
                    else if (thisOverOther != null && NoMultiplicativeOverOrUnderFlow(thisConstant, otherConstant, thisOverOther))
                    {
                        if (thisOverOtherLength <= thisConstant.ToCode().Length + otherConstant.ToCode().Length + 1)
                        {
                            // keep the order, but opposite operator
                            rightOperator.OperatorToken = JSToken.Multiply;
                            RotateFromRight(node, rightOperator, thisOverOther);
                        }
                    }
                }
            }
            else if (node.OperatorToken == JSToken.Divide)
            {
                if (rightOperator.OperatorToken == JSToken.Multiply)
                {
                    // divide-mult
                    ConstantWrapper newLiteral = Divide(thisConstant, otherConstant);
                    if (newLiteral != null && NoMultiplicativeOverOrUnderFlow(thisConstant, otherConstant, newLiteral)
                        && newLiteral.ToCode().Length <= thisConstant.ToCode().Length + otherConstant.ToCode().Length + 1)
                    {
                        // swap the operands
                        rightOperator.SwapOperands();

                        // change the operator
                        rightOperator.OperatorToken = JSToken.Divide;
                        RotateFromRight(node, rightOperator, newLiteral);
                    }
                }
                else if (rightOperator.OperatorToken == JSToken.Divide)
                {
                    // divide-divide
                    ConstantWrapper newLiteral = Multiply(thisConstant, otherConstant);
                    if (newLiteral != null && NoMultiplicativeOverOrUnderFlow(thisConstant, otherConstant, newLiteral))
                    {
                        // but we need to swap the left and right operands first
                        rightOperator.SwapOperands();

                        // then rotate the node up after replacing old with new
                        RotateFromRight(node, rightOperator, newLiteral);
                    }
                }
            }
        }
Esempio n. 30
0
        // called during ConstantWrapper.AnalyzeNode
        internal virtual List <ConstantWrapper> AddLiteral(ConstantWrapper constantWrapper, ActivationObject refScope)
        {
            List <ConstantWrapper> nodeList = null;

            // numeric constants that are NaN or Infinity need not apply
            if (!constantWrapper.IsSpecialNumeric)
            {
                // if the constant is only one character long, it's never a good idea to
                // try and replace it
                string constantValue = constantWrapper.ToCode();
                if (constantValue.Length > 1)
                {
                    // go up the chain recursively. return the highest shared
                    // constant node list so we can share it if we need to
                    nodeList = ((ActivationObject)Parent).AddLiteral(constantWrapper, this);

                    // if we haven't created our literal map yet, do so now
                    if (m_literalMap == null)
                    {
                        m_literalMap = new Dictionary <string, LiteralReference>();
                    }

                    // now handle our scope
                    LiteralReference literalReference;
                    // see if this constant is in our map
                    if (m_literalMap.ContainsKey(constantValue))
                    {
                        literalReference = m_literalMap[constantValue];
                        // increment the counter
                        literalReference.Increment();
                        // add this constant wrapper to the list
                        if (!literalReference.ConstantWrapperList.Contains(constantWrapper))
                        {
                            literalReference.ConstantWrapperList.Add(constantWrapper);
                        }

                        // if this is the ref scope, or if the ref scope is not the child scope,
                        // set the child scope to null
                        if (literalReference.ChildScope != null &&
                            (refScope == this || refScope != literalReference.ChildScope))
                        {
                            literalReference.ChildScope = null;
                        }
                    }
                    else
                    {
                        // add to the table with count = 1 and our given constant wrapper
                        // if this is the ref scope, child scope is null; otherwise use refScope
                        // if nodelist is null, create a new list; otherwise use the shared list
                        literalReference = new LiteralReference(
                            constantWrapper,
                            (refScope != this ? refScope : null),
                            nodeList
                            );
                        m_literalMap.Add(constantValue, literalReference);
                    }

                    // return whatever list it is we used for our node.
                    // it might be shared, or it might be new if we didn't find a shared list
                    nodeList = literalReference.ConstantWrapperList;
                }
            }

            return(nodeList);
        }
Esempio n. 31
0
 // the global scope does nothing when told to add literals -- just returns null
 internal override List<ConstantWrapper> AddLiteral(ConstantWrapper constantWrapper, ActivationObject refScope)
 {
     return null;
 }
Esempio n. 32
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;
        }
Esempio n. 33
0
        private ConstantWrapper StringConcat(ConstantWrapper left, ConstantWrapper right)
        {
            ConstantWrapper newLiteral = null;

            // if we don't want to combine adjacent string literals, then we know we don't want to do
            // anything here.
            if (m_parser.Settings.IsModificationAllowed(TreeModifications.CombineAdjacentStringLiterals))
            {
                // if either one of the operands is not a string literal, then check to see if we allow
                // evaluation of numeric expression; if not, then no-go. IF they are both string literals,
                // then it doesn't matter what the numeric flag says.
                if ((left.IsStringLiteral && right.IsStringLiteral)
                    || m_parser.Settings.IsModificationAllowed(TreeModifications.EvaluateNumericExpressions))
                {
                    // if either value is a floating-point number (a number, not NaN, not Infinite, not an Integer),
                    // then we won't do the string concatenation because different browsers may have subtle differences
                    // in their double-to-string conversion algorithms.
                    // so if neither is a numeric literal, or if one or both are, if they are both integer literals
                    // in the range that we can EXACTLY represent them in a double, then we can proceed.
                    // NaN, +Infinity and -Infinity are also acceptable
                    if ((!left.IsNumericLiteral || left.IsExactInteger || left.IsNaN || left.IsInfinity)
                        && (!right.IsNumericLiteral || right.IsExactInteger || right.IsNaN || right.IsInfinity))
                    {
                        // they are both either string, bool, null, or integer
                        newLiteral = new ConstantWrapper(left.ToString() + right.ToString(), PrimitiveType.String, null, m_parser);
                    }
                }
            }

            return newLiteral;
        }
Esempio n. 34
0
        //---------------------------------------------------------------------------------------
        // ParseWhileStatement
        //
        //  WhileStatement :
        //    'while' '(' Expression ')' Statement
        //---------------------------------------------------------------------------------------
        private WhileNode ParseWhileStatement()
        {
            Context whileCtx = m_currentToken.Clone();
            AstNode condition = null;
            AstNode body = null;
            m_blockType.Add(BlockType.Loop);
            try
            {
                GetNextToken();
                if (JSToken.LeftParenthesis != m_currentToken.Token)
                {
                    ReportError(JSError.NoLeftParenthesis);
                }
                GetNextToken();
                m_noSkipTokenSet.Add(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet);
                try
                {
                    condition = ParseExpression();
                    if (JSToken.RightParenthesis != m_currentToken.Token)
                    {
                        ReportError(JSError.NoRightParenthesis);
                        whileCtx.UpdateWith(condition.Context);
                    }
                    else
                        whileCtx.UpdateWith(m_currentToken);

                    GetNextToken();
                }
                catch (RecoveryTokenException exc)
                {
                    if (IndexOfToken(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet, exc) == -1)
                    {
                        // abort the while there is really no much to do here
                        exc._partiallyComputedNode = null;
                        throw;
                    }
                    else
                    {
                        // make up a condition
                        if (exc._partiallyComputedNode != null)
                            condition = exc._partiallyComputedNode;
                        else
                            condition = new ConstantWrapper(false, PrimitiveType.Boolean, CurrentPositionContext(), this);

                        if (JSToken.RightParenthesis == m_currentToken.Token)
                            GetNextToken();
                    }
                }
                finally
                {
                    m_noSkipTokenSet.Remove(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet);
                }

                // if the statements aren't withing curly-braces, throw a possible error
                if (JSToken.LeftCurly != m_currentToken.Token)
                {
                    ReportError(JSError.StatementBlockExpected, whileCtx, true);
                }
                try
                {
                    // parse a Statement, not a SourceElement
                    body = ParseStatement(false);
                }
                catch (RecoveryTokenException exc)
                {
                    if (exc._partiallyComputedNode != null)
                        body = exc._partiallyComputedNode;
                    else
                        body = new Block(CurrentPositionContext(), this);

                    exc._partiallyComputedNode = new WhileNode(whileCtx, this, condition, body);
                    throw;
                }

            }
            finally
            {
                m_blockType.RemoveAt(m_blockType.Count - 1);
            }

            return new WhileNode(whileCtx, this, condition, body);
        }
Esempio n. 35
0
        /// <summary>
        /// We have determined that our right-hand operand is another binary operator, and its
        /// left-hand operand is a constant that can be combined with our left-hand operand.
        /// Now we want to set the left-hand operand of that other operator to the newly-
        /// combined constant value, and then rotate it up -- replace our binary operator
        /// with this newly-modified binary operator, and then attempt to re-evaluate it.
        /// </summary>
        /// <param name="binaryOp">the binary operator that is our right-hand operand</param>
        /// <param name="newLiteral">the newly-combined literal</param>
        private void RotateFromRight(BinaryOperator node, BinaryOperator binaryOp, ConstantWrapper newLiteral)
        {
            // replace our node with the binary operator
            binaryOp.ReplaceChild(binaryOp.Operand1, newLiteral);
            node.Parent.ReplaceChild(node, binaryOp);

            // and just for good measure.. revisit the node that's taking our place, since
            // we just changed a constant value. Assuming the other operand is a constant, too.
            ConstantWrapper otherConstant = binaryOp.Operand2 as ConstantWrapper;
            if (otherConstant != null)
            {
                EvalThisOperator(binaryOp, newLiteral, otherConstant);
            }
        }
Esempio n. 36
0
        //---------------------------------------------------------------------------------------
        // ParseSwitchStatement
        //
        //  SwitchStatement :
        //    'switch' '(' Expression ')' '{' CaseBlock '}'
        //
        //  CaseBlock :
        //    CaseList DefaultCaseClause CaseList
        //
        //  CaseList :
        //    <empty> |
        //    CaseClause CaseList
        //
        //  CaseClause :
        //    'case' Expression ':' OptionalStatements
        //
        //  DefaultCaseClause :
        //    <empty> |
        //    'default' ':' OptionalStatements
        //---------------------------------------------------------------------------------------
        private AstNode ParseSwitchStatement()
        {
            Context switchCtx = m_currentToken.Clone();
            AstNode expr = null;
            AstNodeList cases = null;
            m_blockType.Add(BlockType.Switch);
            try
            {
                // read switch(expr)
                GetNextToken();
                if (JSToken.LeftParenthesis != m_currentToken.Token)
                    ReportError(JSError.NoLeftParenthesis);
                GetNextToken();
                m_noSkipTokenSet.Add(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet);
                m_noSkipTokenSet.Add(NoSkipTokenSet.s_SwitchNoSkipTokenSet);
                try
                {
                    expr = ParseExpression();

                    if (JSToken.RightParenthesis != m_currentToken.Token)
                    {
                        ReportError(JSError.NoRightParenthesis);
                    }

                    GetNextToken();
                    if (JSToken.LeftCurly != m_currentToken.Token)
                    {
                        ReportError(JSError.NoLeftCurly);
                    }
                    GetNextToken();

                }
                catch (RecoveryTokenException exc)
                {
                    if (IndexOfToken(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet, exc) == -1
                          && IndexOfToken(NoSkipTokenSet.s_SwitchNoSkipTokenSet, exc) == -1)
                    {
                        // give up
                        exc._partiallyComputedNode = null;
                        throw;
                    }
                    else
                    {
                        if (exc._partiallyComputedNode == null)
                            expr = new ConstantWrapper(true, PrimitiveType.Boolean, CurrentPositionContext(), this);
                        else
                            expr = exc._partiallyComputedNode;

                        if (IndexOfToken(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet, exc) != -1)
                        {
                            if (exc._token == JSToken.RightParenthesis)
                                GetNextToken();

                            if (JSToken.LeftCurly != m_currentToken.Token)
                            {
                                ReportError(JSError.NoLeftCurly);
                            }
                            GetNextToken();
                        }

                    }
                }
                finally
                {
                    m_noSkipTokenSet.Remove(NoSkipTokenSet.s_SwitchNoSkipTokenSet);
                    m_noSkipTokenSet.Remove(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet);
                }

                // parse the switch body
                cases = new AstNodeList(m_currentToken.Clone(), this);
                bool defaultStatement = false;
                m_noSkipTokenSet.Add(NoSkipTokenSet.s_BlockNoSkipTokenSet);
                try
                {
                    while (JSToken.RightCurly != m_currentToken.Token)
                    {
                        SwitchCase caseClause = null;
                        AstNode caseValue = null;
                        Context caseCtx = m_currentToken.Clone();
                        m_noSkipTokenSet.Add(NoSkipTokenSet.s_CaseNoSkipTokenSet);
                        try
                        {
                            if (JSToken.Case == m_currentToken.Token)
                            {
                                // get the case
                                GetNextToken();
                                caseValue = ParseExpression();
                            }
                            else if (JSToken.Default == m_currentToken.Token)
                            {
                                // get the default
                                if (defaultStatement)
                                {
                                    // we report an error but we still accept the default
                                    ReportError(JSError.DupDefault, true);
                                }
                                else
                                {
                                    defaultStatement = true;
                                }
                                GetNextToken();
                            }
                            else
                            {
                                // This is an error, there is no case or default. Assume a default was missing and keep going
                                defaultStatement = true;
                                ReportError(JSError.BadSwitch);
                            }
                            if (JSToken.Colon != m_currentToken.Token)
                            {
                                ReportError(JSError.NoColon);
                            }

                            // read the statements inside the case or default
                            GetNextToken();
                        }
                        catch (RecoveryTokenException exc)
                        {
                            // right now we can only get here for the 'case' statement
                            if (IndexOfToken(NoSkipTokenSet.s_CaseNoSkipTokenSet, exc) == -1)
                            {
                                // ignore the current case or default
                                exc._partiallyComputedNode = null;
                                throw;
                            }
                            else
                            {
                                caseValue = exc._partiallyComputedNode;

                                if (exc._token == JSToken.Colon)
                                {
                                    GetNextToken();
                                }
                            }
                        }
                        finally
                        {
                            m_noSkipTokenSet.Remove(NoSkipTokenSet.s_CaseNoSkipTokenSet);
                        }

                        m_blockType.Add(BlockType.Block);
                        try
                        {
                            Block statements = new Block(m_currentToken.Clone(), this);
                            m_noSkipTokenSet.Add(NoSkipTokenSet.s_SwitchNoSkipTokenSet);
                            m_noSkipTokenSet.Add(NoSkipTokenSet.s_StartStatementNoSkipTokenSet);
                            try
                            {
                                while (JSToken.RightCurly != m_currentToken.Token && JSToken.Case != m_currentToken.Token && JSToken.Default != m_currentToken.Token)
                                {
                                    try
                                    {
                                        // parse a Statement, not a SourceElement
                                        statements.Append(ParseStatement(false));
                                    }
                                    catch (RecoveryTokenException exc)
                                    {
                                        if (exc._partiallyComputedNode != null)
                                        {
                                            statements.Append(exc._partiallyComputedNode);
                                            exc._partiallyComputedNode = null;
                                        }
                                        if (IndexOfToken(NoSkipTokenSet.s_StartStatementNoSkipTokenSet, exc) == -1)
                                        {
                                            throw;
                                        }
                                    }
                                }
                            }
                            catch (RecoveryTokenException exc)
                            {
                                if (IndexOfToken(NoSkipTokenSet.s_SwitchNoSkipTokenSet, exc) == -1)
                                {
                                    caseClause = new SwitchCase(caseCtx, this, caseValue, statements);
                                    cases.Append(caseClause);
                                    throw;
                                }
                            }
                            finally
                            {
                                m_noSkipTokenSet.Remove(NoSkipTokenSet.s_StartStatementNoSkipTokenSet);
                                m_noSkipTokenSet.Remove(NoSkipTokenSet.s_SwitchNoSkipTokenSet);
                            }
                            if (JSToken.RightCurly == m_currentToken.Token)
                            {
                                statements.Context.UpdateWith(m_currentToken);
                            }
                            caseCtx.UpdateWith(statements.Context);
                            caseClause = new SwitchCase(caseCtx, this, caseValue, statements);
                            cases.Append(caseClause);
                        }
                        finally
                        {
                            m_blockType.RemoveAt(m_blockType.Count - 1);
                        }
                    }
                }
                catch (RecoveryTokenException exc)
                {
                    if (IndexOfToken(NoSkipTokenSet.s_BlockNoSkipTokenSet, exc) == -1)
                    {
                        //save what you can a rethrow
                        switchCtx.UpdateWith(CurrentPositionContext());
                        exc._partiallyComputedNode = new Switch(switchCtx, this, expr, cases);
                        throw;
                    }
                }
                finally
                {
                    m_noSkipTokenSet.Remove(NoSkipTokenSet.s_BlockNoSkipTokenSet);
                }
                switchCtx.UpdateWith(m_currentToken);
                GetNextToken();
            }
            finally
            {
                m_blockType.RemoveAt(m_blockType.Count - 1);
            }

            return new Switch(switchCtx, this, expr, cases);
        }
Esempio n. 37
0
        /// <summary>
        /// If the new literal is a string literal, then we need to check to see if our
        /// parent is a CallNode. If it is, and if the string literal can be an identifier,
        /// we'll replace it with a Member-Dot operation.
        /// </summary>
        /// <param name="newLiteral">newLiteral we intend to replace this binaryop node with</param>
        /// <returns>true if we replaced the parent callnode with a member-dot operation</returns>
        private bool ReplaceMemberBracketWithDot(BinaryOperator node, ConstantWrapper newLiteral)
        {
            if (newLiteral.IsStringLiteral)
            {
                // see if this newly-combined string is the sole argument to a
                // call-brackets node. If it is and the combined string is a valid
                // identifier (and not a keyword), then we can replace the call
                // with a member operator.
                // remember that the parent of the argument won't be the call node -- it
                // will be the ast node list representing the arguments, whose parent will
                // be the node list.
                CallNode parentCall = (node.Parent is AstNodeList ? node.Parent.Parent as CallNode : null);
                if (parentCall != null && parentCall.InBrackets)
                {
                    // get the newly-combined string
                    string combinedString = newLiteral.ToString();

                    // see if this new string is the target of a replacement operation
                    string newName;
                    if (m_parser.Settings.HasRenamePairs && m_parser.Settings.ManualRenamesProperties
                        && m_parser.Settings.IsModificationAllowed(TreeModifications.PropertyRenaming)
                        && !string.IsNullOrEmpty(newName = m_parser.Settings.GetNewName(combinedString)))
                    {
                        // yes, it is. Now see if the new name is safe to be converted to a dot-operation.
                        if (m_parser.Settings.IsModificationAllowed(TreeModifications.BracketMemberToDotMember)
                            && JSScanner.IsSafeIdentifier(newName)
                            && !JSScanner.IsKeyword(newName, parentCall.EnclosingScope.UseStrict))
                        {
                            // we want to replace the call with operator with a new member dot operation, and
                            // since we won't be analyzing it (we're past the analyze phase, we're going to need
                            // to use the new string value
                            Member replacementMember = new Member(parentCall.Context, m_parser, parentCall.Function, newName, parentCall.Arguments[0].Context);
                            parentCall.Parent.ReplaceChild(parentCall, replacementMember);
                            return true;
                        }
                        else
                        {
                            // nope, can't be changed to a dot-operator for whatever reason.
                            // just replace the value on this new literal. The old operation will
                            // get replaced with this new literal
                            newLiteral.Value = newName;

                            // and make sure it's type is string
                            newLiteral.PrimitiveType = PrimitiveType.String;
                        }
                    }
                    else if (m_parser.Settings.IsModificationAllowed(TreeModifications.BracketMemberToDotMember))
                    {
                        // our parent is a call-bracket -- now we just need to see if the newly-combined
                        // string can be an identifier
                        if (JSScanner.IsSafeIdentifier(combinedString) && !JSScanner.IsKeyword(combinedString, parentCall.EnclosingScope.UseStrict))
                        {
                            // yes -- replace the parent call with a new member node using the newly-combined string
                            Member replacementMember = new Member(parentCall.Context, m_parser, parentCall.Function, combinedString, parentCall.Arguments[0].Context);
                            parentCall.Parent.ReplaceChild(parentCall, replacementMember);
                            return true;
                        }
                    }
                }
            }
            return false;
        }
Esempio n. 38
0
        //---------------------------------------------------------------------------------------
        // MemberExpression
        //
        // Accessor :
        //  <empty> |
        //  Arguments Accessor
        //  '[' Expression ']' Accessor |
        //  '.' Identifier Accessor |
        //
        //  Don't have this function throwing an exception without checking all the calling sites.
        //  There is state in instance variable that is saved on the calling stack in some function
        //  (i.e ParseFunction and ParseClass) and you don't want to blow up the stack
        //---------------------------------------------------------------------------------------
        private AstNode MemberExpression(AstNode expression, List<Context> newContexts)
        {
            for (; ; )
            {
                m_noSkipTokenSet.Add(NoSkipTokenSet.s_MemberExprNoSkipTokenSet);
                try
                {
                    switch (m_currentToken.Token)
                    {
                        case JSToken.LeftParenthesis:
                            AstNodeList args = null;
                            RecoveryTokenException callError = null;
                            m_noSkipTokenSet.Add(NoSkipTokenSet.s_ParenToken);
                            try
                            {
                                args = ParseExpressionList(JSToken.RightParenthesis);
                            }
                            catch (RecoveryTokenException exc)
                            {
                                args = (AstNodeList)exc._partiallyComputedNode;
                                if (IndexOfToken(NoSkipTokenSet.s_ParenToken, exc) == -1)
                                    callError = exc; // thrown later on
                            }
                            finally
                            {
                                m_noSkipTokenSet.Remove(NoSkipTokenSet.s_ParenToken);
                            }

                            expression = new CallNode(expression.Context.CombineWith(args.Context), this, expression, args, false);

                            if (null != newContexts && newContexts.Count > 0)
                            {
                                (newContexts[newContexts.Count - 1]).UpdateWith(expression.Context);
                                if (!(expression is CallNode))
                                    expression = new CallNode(newContexts[newContexts.Count - 1], this, expression, new AstNodeList(CurrentPositionContext(), this), false);
                                else
                                    expression.Context = newContexts[newContexts.Count - 1];
                                ((CallNode)expression).IsConstructor = true;
                                newContexts.RemoveAt(newContexts.Count - 1);
                            }

                            if (callError != null)
                            {
                                callError._partiallyComputedNode = expression;
                                throw callError;
                            }

                            GetNextToken();
                            break;

                        case JSToken.LeftBracket:
                            m_noSkipTokenSet.Add(NoSkipTokenSet.s_BracketToken);
                            try
                            {
                                //
                                // ROTOR parses a[b,c] as a call to a, passing in the arguments b and c.
                                // the correct parse is a member lookup on a of c -- the "b,c" should be
                                // a single expression with a comma operator that evaluates b but only
                                // returns c.
                                // So we'll change the default behavior from parsing an expression list to
                                // parsing a single expression, but returning a single-item list (or an empty
                                // list if there is no expression) so the rest of the code will work.
                                //
                                //args = ParseExpressionList(JSToken.RightBracket);
                                GetNextToken();
                                args = new AstNodeList(m_currentToken.Clone(), this);

                                AstNode accessor = ParseExpression();
                                if (accessor != null)
                                {
                                    args.Append(accessor);
                                }
                            }
                            catch (RecoveryTokenException exc)
                            {
                                if (IndexOfToken(NoSkipTokenSet.s_BracketToken, exc) == -1)
                                {
                                    if (exc._partiallyComputedNode != null)
                                    {
                                        exc._partiallyComputedNode =
                                           new CallNode(expression.Context.CombineWith(m_currentToken.Clone()), this, expression, (AstNodeList)exc._partiallyComputedNode, true);
                                    }
                                    else
                                    {
                                        exc._partiallyComputedNode = expression;
                                    }
                                    throw;
                                }
                                else
                                    args = (AstNodeList)exc._partiallyComputedNode;
                            }
                            finally
                            {
                                m_noSkipTokenSet.Remove(NoSkipTokenSet.s_BracketToken);
                            }
                            expression = new CallNode(expression.Context.CombineWith(m_currentToken.Clone()), this, expression, args, true);

                            // there originally was code here in the ROTOR sources that checked the new context list and
                            // changed this member call to a constructor call, effectively combining the two. I believe they
                            // need to remain separate.

                            // remove the close bracket token
                            GetNextToken();
                            break;

                        case JSToken.AccessField:
                            ConstantWrapper id = null;
                            GetNextToken();
                            if (JSToken.Identifier != m_currentToken.Token)
                            {
                                string identifier = JSKeyword.CanBeIdentifier(m_currentToken.Token);
                                if (null != identifier)
                                {
                                    // don't report an error here -- it's actually okay to have a property name
                                    // that is a keyword which is okay to be an identifier. For instance,
                                    // jQuery has a commonly-used method named "get" to make an ajax request
                                    //ForceReportInfo(JSError.KeywordUsedAsIdentifier);
                                    id = new ConstantWrapper(identifier, PrimitiveType.String, m_currentToken.Clone(), this);
                                }
                                else if (JSScanner.IsValidIdentifier(m_currentToken.Code))
                                {
                                    // it must be a keyword, because it can't technically be an indentifier,
                                    // but it IS a valid identifier format. Throw the error but still
                                    // create the constant wrapper so we can output it as-is
                                    ReportError(JSError.NoIdentifier, m_currentToken.Clone(), true);
                                    id = new ConstantWrapper(m_currentToken.Code, PrimitiveType.String, m_currentToken.Clone(), this);
                                }
                                else
                                {
                                    ReportError(JSError.NoIdentifier);
                                    SkipTokensAndThrow(expression);
                                }
                            }
                            else
                            {
                                id = new ConstantWrapper(m_scanner.GetIdentifier(), PrimitiveType.String, m_currentToken.Clone(), this);
                            }
                            GetNextToken();
                            expression = new Member(expression.Context.CombineWith(id.Context), this, expression, id.Context.Code, id.Context);
                            break;
                        default:
                            if (null != newContexts)
                            {
                                while (newContexts.Count > 0)
                                {
                                    (newContexts[newContexts.Count - 1]).UpdateWith(expression.Context);
                                    expression = new CallNode(newContexts[newContexts.Count - 1],
                                                          this,
                                                          expression,
                                                          new AstNodeList(CurrentPositionContext(), this),
                                                          false);
                                    ((CallNode)expression).IsConstructor = true;
                                    newContexts.RemoveAt(newContexts.Count - 1);
                                }
                            }
                            return expression;
                    }
                }
                catch (RecoveryTokenException exc)
                {
                    if (IndexOfToken(NoSkipTokenSet.s_MemberExprNoSkipTokenSet, exc) != -1)
                        expression = exc._partiallyComputedNode;
                    else
                    {
                        Debug.Assert(exc._partiallyComputedNode == expression);
                        throw;
                    }
                }
                finally
                {
                    m_noSkipTokenSet.Remove(NoSkipTokenSet.s_MemberExprNoSkipTokenSet);
                }
            }
        }
Esempio n. 39
0
        private static string CreateJSFromResourceStrings(ResourceStrings resourceStrings)
        {
            var sb = StringBuilderPool.Acquire();

            try
            {
                // start the var statement using the requested name and open the initializer object literal
                sb.Append("var ");
                sb.Append(resourceStrings.Name);
                sb.Append("={");

                // we're going to need to insert commas between each pair, so we'll use a boolean
                // flag to indicate that we're on the first pair. When we output the first pair, we'll
                // set the flag to false. When the flag is false, we're about to insert another pair, so
                // we'll add the comma just before.
                bool firstItem = true;

                // loop through all items in the collection
                foreach (var keyPair in resourceStrings.NameValuePairs)
                {
                    // if this isn't the first item, we need to add a comma separator
                    if (!firstItem)
                    {
                        sb.Append(',');
                    }
                    else
                    {
                        // next loop is no longer the first item
                        firstItem = false;
                    }

                    // append the key as the name, a colon to separate the name and value,
                    // and then the value
                    // must quote if not valid JS identifier format, or if it is, but it's a keyword
                    // (use strict mode just to be safe)
                    string propertyName = keyPair.Key;
                    if (!JSScanner.IsValidIdentifier(propertyName) || JSScanner.IsKeyword(propertyName, true))
                    {
                        sb.Append("\"");
                        // because we are using quotes for the delimiters, replace any instances
                        // of a quote character (") with an escaped quote character (\")
                        sb.Append(propertyName.Replace("\"", "\\\""));
                        sb.Append("\"");
                    }
                    else
                    {
                        sb.Append(propertyName);
                    }
                    sb.Append(':');

                    // make sure the Value is properly escaped, quoted, and whatever we
                    // need to do to make sure it's a proper JS string.
                    // pass false for whether this string is an argument to a RegExp constructor.
                    // pass false for whether to use W3Strict formatting for character escapes (use maximum browser compatibility)
                    // pass true for ecma strict mode
                    string stringValue = ConstantWrapper.EscapeString(
                        keyPair.Value,
                        false,
                        false,
                        true
                        );
                    sb.Append(stringValue);
                }

                // close the object literal and return the string
                sb.AppendLine("};");
                return(sb.ToString());
            }
            finally
            {
                sb.Release();
            }
        }
Esempio n. 40
0
        private ConstantWrapper Plus(ConstantWrapper left, ConstantWrapper right)
        {
            ConstantWrapper newLiteral = null;

            if (left.IsStringLiteral || right.IsStringLiteral)
            {
                // one or both are strings -- this is a strng concat operation
                newLiteral = StringConcat(left, right);
            }
            else
            {
                // neither are strings -- this is a numeric addition operation
                newLiteral = NumericAddition(left, right);
            }
            return newLiteral;
        }
Esempio n. 41
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;
        }
Esempio n. 42
0
        public override void CleanupNodes()
        {
            base.CleanupNodes();

            // see if the condition is a constant
            if (Parser.Settings.EvalLiteralExpressions &&
                Parser.Settings.IsModificationAllowed(TreeModifications.EvaluateNumericExpressions))
            {
                ConstantWrapper constantCondition = Condition as ConstantWrapper;
                if (constantCondition != null)
                {
                    // TODO: we'd RATHER eliminate the statement altogether if the condition is always false,
                    // but we'd need to make sure var'd variables and declared functions are properly handled.
                    try
                    {
                        bool isTrue = constantCondition.ToBoolean();
                        if (isTrue)
                        {
                            // the condition is always true; we should change it to a for(;;) statement.
                            // less bytes than while(1)

                            // check to see if we want to combine a preceding var with a for-statement
                            AstNode initializer = null;
                            if (Parser.Settings.IsModificationAllowed(TreeModifications.MoveVarIntoFor))
                            {
                                // if the previous statement is a var, we can move it to the initializer
                                // and save even more bytes. The parent should always be a block. If not,
                                // then assume there is no previous.
                                Block parentBlock = Parent as Block;
                                if (parentBlock != null)
                                {
                                    int whileIndex = parentBlock.StatementIndex(this);
                                    if (whileIndex > 0)
                                    {
                                        Var previousVar = parentBlock[whileIndex - 1] as Var;
                                        if (previousVar != null)
                                        {
                                            initializer = previousVar;
                                            parentBlock.ReplaceChild(previousVar, null);
                                        }
                                    }
                                }
                            }

                            // create the for using our body and replace ourselves with it
                            ForNode forNode = new ForNode(Context, Parser, initializer, null, null, Body);
                            Parent.ReplaceChild(this, forNode);
                        }
                        else if (constantCondition.IsNotOneOrPositiveZero)
                        {
                            // the condition is always false, so we can replace the condition
                            // with a zero -- only one byte
                            Condition = new ConstantWrapper(0, PrimitiveType.Number, null, Parser);
                        }
                    }
                    catch (InvalidCastException)
                    {
                        // ignore any invalid cast exceptions
                    }
                }
            }
        }
Esempio n. 43
0
        /// <summary>
        /// Evaluate: (OTHER [op] CONST) [op] CONST
        /// </summary>
        /// <param name="thisConstant">second constant</param>
        /// <param name="otherConstant">first constant</param>
        /// <param name="leftOperator">first operator</param>
        private void EvalToTheLeft(BinaryOperator node, ConstantWrapper thisConstant, ConstantWrapper otherConstant, BinaryOperator leftOperator)
        {
            if (leftOperator.OperatorToken == JSToken.Plus && node.OperatorToken == JSToken.Plus)
            {
                // plus-plus
                // the other operation goes first, so if the other constant is a string, then we know that
                // operation will do a string concatenation, which will force our operation to be a string
                // concatenation. If the other constant is not a string, then we won't know until runtime and
                // we can't combine them.
                if (otherConstant.IsStringLiteral)
                {
                    // the other constant is a string -- so we can do the string concat and combine them
                    ConstantWrapper newLiteral = StringConcat(otherConstant, thisConstant);
                    if (newLiteral != null)
                    {
                        RotateFromLeft(node, leftOperator, newLiteral);
                    }
                }
            }
            else if (leftOperator.OperatorToken == JSToken.Minus)
            {
                if (node.OperatorToken == JSToken.Plus)
                {
                    // minus-plus
                    // the minus operator goes first and will always convert to number.
                    // if our constant is not a string, then it will be a numeric addition and we can combine them.
                    // if our constant is a string, then we'll end up doing a string concat, so we can't combine
                    if (!thisConstant.IsStringLiteral)
                    {
                        // two numeric operators. a-n1+n2 is the same as a-(n1-n2)
                        ConstantWrapper newLiteral = Minus(otherConstant, thisConstant);
                        if (newLiteral != null && NoOverflow(newLiteral))
                        {
                            // a-(-n) is numerically equivalent as a+n -- and takes fewer characters to represent.
                            // BUT we can't do that because that might change a numeric operation (the original minus)
                            // to a string concatenation if the unknown operand turns out to be a string!

                            RotateFromLeft(node, leftOperator, newLiteral);
                        }
                        else
                        {
                            // if the left-left is a constant, then we can try combining with it
                            ConstantWrapper leftLeft = leftOperator.Operand1 as ConstantWrapper;
                            if (leftLeft != null)
                            {
                                EvalFarToTheLeft(node, thisConstant, leftLeft, leftOperator);
                            }
                        }
                    }
                }
                else if (node.OperatorToken == JSToken.Minus)
                {
                    // minus-minus. Both operations are numeric.
                    // a-n1-n2 => a-(n1+n2), so we can add the two constants and subtract from
                    // the left-hand non-constant.
                    ConstantWrapper newLiteral = NumericAddition(otherConstant, thisConstant);
                    if (newLiteral != null && NoOverflow(newLiteral))
                    {
                        // make it the new right-hand literal for the left-hand operator
                        // and make the left-hand operator replace our operator
                        RotateFromLeft(node, leftOperator, newLiteral);
                    }
                    else
                    {
                        // if the left-left is a constant, then we can try combining with it
                        ConstantWrapper leftLeft = leftOperator.Operand1 as ConstantWrapper;
                        if (leftLeft != null)
                        {
                            EvalFarToTheLeft(node, thisConstant, leftLeft, leftOperator);
                        }
                    }
                }
            }
            else if (leftOperator.OperatorToken == node.OperatorToken
                && (node.OperatorToken == JSToken.Multiply || node.OperatorToken == JSToken.Divide))
            {
                // either multiply-multiply or divide-divide
                // either way, we use the other operand and the product of the two constants.
                // if the product blows up to an infinte value, then don't combine them because that
                // could change the way the program goes at runtime, depending on the unknown value.
                ConstantWrapper newLiteral = Multiply(otherConstant, thisConstant);
                if (newLiteral != null && NoMultiplicativeOverOrUnderFlow(otherConstant, thisConstant, newLiteral))
                {
                    RotateFromLeft(node, leftOperator, newLiteral);
                }
            }
            else if ((leftOperator.OperatorToken == JSToken.Multiply && node.OperatorToken == JSToken.Divide)
                || (leftOperator.OperatorToken == JSToken.Divide && node.OperatorToken == JSToken.Multiply))
            {
                if (m_parser.Settings.IsModificationAllowed(TreeModifications.EvaluateNumericExpressions))
                {
                    // get the two division operators
                    ConstantWrapper otherOverThis = Divide(otherConstant, thisConstant);
                    ConstantWrapper thisOverOther = Divide(thisConstant, otherConstant);

                    // get the lengths
                    int otherOverThisLength = otherOverThis != null ? otherOverThis.ToCode().Length : int.MaxValue;
                    int thisOverOtherLength = thisOverOther != null ? thisOverOther.ToCode().Length : int.MaxValue;

                    // we'll want to use whichever one is shorter, and whichever one does NOT involve an overflow
                    // or possible underflow
                    if (otherOverThis != null && NoMultiplicativeOverOrUnderFlow(otherConstant, thisConstant, otherOverThis)
                        && (thisOverOther == null || otherOverThisLength < thisOverOtherLength))
                    {
                        // but only if it's smaller than the original expression
                        if (otherOverThisLength <= otherConstant.ToCode().Length + thisConstant.ToCode().Length + 1)
                        {
                            // same operator
                            RotateFromLeft(node, leftOperator, otherOverThis);
                        }
                    }
                    else if (thisOverOther != null && NoMultiplicativeOverOrUnderFlow(thisConstant, otherConstant, thisOverOther))
                    {
                        // but only if it's smaller than the original expression
                        if (thisOverOtherLength <= otherConstant.ToCode().Length + thisConstant.ToCode().Length + 1)
                        {
                            // opposite operator
                            leftOperator.OperatorToken = leftOperator.OperatorToken == JSToken.Multiply ? JSToken.Divide : JSToken.Multiply;
                            RotateFromLeft(node, leftOperator, thisOverOther);
                        }
                    }
                }
            }
            else if (node.OperatorToken == leftOperator.OperatorToken
                && (node.OperatorToken == JSToken.BitwiseAnd || node.OperatorToken == JSToken.BitwiseOr || node.OperatorToken == JSToken.BitwiseXor))
            {
                // identical bitwise operators can be combined
                ConstantWrapper newLiteral = null;
                switch (node.OperatorToken)
                {
                    case JSToken.BitwiseAnd:
                        newLiteral = BitwiseAnd(otherConstant, thisConstant);
                        break;

                    case JSToken.BitwiseOr:
                        newLiteral = BitwiseOr(otherConstant, thisConstant);
                        break;

                    case JSToken.BitwiseXor:
                        newLiteral = BitwiseXor(otherConstant, thisConstant);
                        break;
                }
                if (newLiteral != null)
                {
                    RotateFromLeft(node, leftOperator, newLiteral);
                }
            }
        }
Esempio n. 44
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;
        }
Esempio n. 45
0
        public override void Visit(ConstantWrapper node)
        {
            if (node != null)
            {
                // check to see if this node is an argument to a RegExp constructor.
                // if it is, we'll want to not use certain string escapes
                AstNode previousNode = null;
                AstNode parentNode = node.Parent;
                while (parentNode != null)
                {
                    // is this a call node and the previous node was one of the parameters?
                    CallNode callNode = parentNode as CallNode;
                    if (callNode != null && previousNode == callNode.Arguments)
                    {
                        // are we calling a simple lookup for "RegExp"?
                        Lookup lookup = callNode.Function as Lookup;
                        if (lookup != null && lookup.Name == "RegExp")
                        {
                            // we are -- so all string literals passed within this constructor should not use
                            // standard string escape sequences
                            node.IsParameterToRegExp = true;
                            // we can stop looking
                            break;
                        }
                    }

                    // next up the chain, keeping track of this current node as next iteration's "previous" node
                    previousNode = parentNode;
                    parentNode = parentNode.Parent;
                }

                // we only need to process the literals IF we are actually going to do
                // anything with them (combine duplicates). So if we aren't, don't call
                // AddLiteral because it hugely inflates the processing time of the application.
                if (m_parser.Settings.CombineDuplicateLiterals)
                {
                    // add this literal to the scope's literal collection.
                    // HOWEVER, we do NOT want to add it for consideration of literal combination
                    // if any scope above us is a with-scope -- otherwise the
                    // variable we use to combine the literals might be confused with a
                    // property on the with-object.
                    // AND we don't want to do it if the scope is unknown, for the same reason.
                    // we won't really know if the variable we create will interfere with the
                    // scope resolution of any variables that me in the eval string.
                    ActivationObject thisScope = ScopeStack.Peek();
                    if (thisScope.IsKnownAtCompileTime && !thisScope.IsInWithScope)
                    {
                        thisScope.AddLiteral(node, thisScope);
                    }
                }

                // this node has no children, so don't bother calling the base
                //base.Visit(node);
            }
        }
Esempio n. 46
0
        internal override void AnalyzeNode()
        {
            // see if this is a member (we'll need it for a couple checks)
            Member member = m_func as Member;

            if (Parser.Settings.StripDebugStatements && Parser.Settings.IsModificationAllowed(TreeModifications.StripDebugStatements))
            {
                // if this is a member, and it's a debugger object, and it's a constructor....
                if (member != null && member.IsDebuggerStatement && m_isConstructor)
                {
                    // we need to replace our debugger object with a generic Object
                    m_func = new Lookup("Object", m_func.Context, Parser);
                    // and make sure the node list is empty
                    if (m_args != null && m_args.Count > 0)
                    {
                        m_args = new AstNodeList(m_args.Context, Parser);
                    }
                }
            }

            // if this is a constructor and we want to collapse
            // some of them to literals...
            if (m_isConstructor && Parser.Settings.CollapseToLiteral)
            {
                // see if this is a lookup, and if so, if it's pointing to one
                // of the two constructors we want to collapse
                Lookup lookup = m_func as Lookup;
                if (lookup != null)
                {
                    if (lookup.Name == "Object" &&
                        Parser.Settings.IsModificationAllowed(TreeModifications.NewObjectToObjectLiteral))
                    {
                        // no arguments -- the Object constructor with no arguments is the exact same as an empty
                        // object literal
                        if (m_args == null || m_args.Count == 0)
                        {
                            // replace our node with an object literal
                            ObjectLiteral objLiteral = new ObjectLiteral(Context, Parser, null, null);
                            if (Parent.ReplaceChild(this, objLiteral))
                            {
                                // and bail now. No need to recurse -- it's an empty literal
                                return;
                            }
                        }
                        else if (m_args.Count == 1)
                        {
                            // one argument
                            // check to see if it's an object literal.
                            ObjectLiteral objectLiteral = m_args[0] as ObjectLiteral;
                            if (objectLiteral != null)
                            {
                                // the Object constructor with an argument that is a JavaScript object merely returns the
                                // argument. Since the argument is an object literal, it is by definition a JavaScript object
                                // and therefore we can replace the constructor call with the object literal
                                Parent.ReplaceChild(this, objectLiteral);

                                // don't forget to recurse the object now
                                objectLiteral.AnalyzeNode();

                                // and then bail -- we don't want to process this call
                                // operation any more; we've gotten rid of it
                                return;
                            }
                        }
                    }
                    else if (lookup.Name == "Array" &&
                             Parser.Settings.IsModificationAllowed(TreeModifications.NewArrayToArrayLiteral))
                    {
                        // Array is trickier.
                        // If there are no arguments, then just use [].
                        // if there are multiple arguments, then use [arg0,arg1...argN].
                        // but if there is one argument and it's numeric, we can't crunch it.
                        // also can't crunch if it's a function call or a member or something, since we won't
                        // KNOW whether or not it's numeric.
                        //
                        // so first see if it even is a single-argument constant wrapper.
                        ConstantWrapper constWrapper = (m_args != null && m_args.Count == 1 ? m_args[0] as ConstantWrapper : null);

                        // if the argument count is not one, then we crunch.
                        // if the argument count IS one, we only crunch if we have a constant wrapper,
                        // AND it's not numeric.
                        if (m_args == null ||
                            m_args.Count != 1 ||
                            (constWrapper != null && !constWrapper.IsNumericLiteral))
                        {
                            // create the new array literal object
                            ArrayLiteral arrayLiteral = new ArrayLiteral(Context, Parser, m_args);
                            // replace ourself within our parent
                            if (Parent.ReplaceChild(this, arrayLiteral))
                            {
                                // recurse
                                arrayLiteral.AnalyzeNode();
                                // and bail -- we don't want to recurse this node any more
                                return;
                            }
                        }
                    }
                }
            }

            // if we are replacing resource references with strings generated from resource files
            // and this is a brackets call: lookup[args]
            ResourceStrings resourceStrings = Parser.ResourceStrings;

            if (m_inBrackets && resourceStrings != null && resourceStrings.Count > 0)
            {
                // see if the root object is a lookup that corresponds to the
                // global value (not a local field) for our resource object
                // (same name)
                Lookup rootLookup = m_func as Lookup;
                if (rootLookup != null &&
                    rootLookup.LocalField == null &&
                    string.CompareOrdinal(rootLookup.Name, resourceStrings.Name) == 0)
                {
                    // we're going to replace this node with a string constant wrapper
                    // but first we need to make sure that this is a valid lookup.
                    // if the parameter contains anything that would vary at run-time,
                    // then we need to throw an error.
                    // the parser will always have either one or zero nodes in the arguments
                    // arg list. We're not interested in zero args, so just make sure there is one
                    if (m_args.Count == 1)
                    {
                        // must be a constant wrapper
                        ConstantWrapper argConstant = m_args[0] as ConstantWrapper;
                        if (argConstant != null)
                        {
                            string resourceName = argConstant.Value.ToString();

                            // get the localized string from the resources object
                            ConstantWrapper resourceLiteral = new ConstantWrapper(
                                resourceStrings[resourceName],
                                PrimitiveType.String,
                                Context,
                                Parser);

                            // replace this node with localized string, analyze it, and bail
                            // so we don't anaylze the tree we just replaced
                            Parent.ReplaceChild(this, resourceLiteral);
                            resourceLiteral.AnalyzeNode();
                            return;
                        }
                        else
                        {
                            // error! must be a constant
                            Context.HandleError(
                                JSError.ResourceReferenceMustBeConstant,
                                true);
                        }
                    }
                    else
                    {
                        // error! can only be a single constant argument to the string resource object.
                        // the parser will only have zero or one arguments, so this must be zero
                        // (since the parser won't pass multiple args to a [] operator)
                        Context.HandleError(
                            JSError.ResourceReferenceMustBeConstant,
                            true);
                    }
                }
            }

            // and finally, if this is a backets call and the argument is a constantwrapper that can
            // be an identifier, just change us to a member node:  obj["prop"] to obj.prop.
            // but ONLY if the string value is "safe" to be an identifier. Even though the ECMA-262
            // spec says certain Unicode categories are okay, in practice the various major browsers
            // all seem to have problems with certain characters in identifiers. Rather than risking
            // some browsers breaking when we change this syntax, don't do it for those "danger" categories.
            if (m_inBrackets && m_args != null)
            {
                // see if there is a single, constant argument
                string argText = m_args.SingleConstantArgument;
                if (argText != null)
                {
                    // see if we want to replace the name
                    string newName;
                    if (Parser.Settings.HasRenamePairs && Parser.Settings.ManualRenamesProperties &&
                        Parser.Settings.IsModificationAllowed(TreeModifications.PropertyRenaming) &&
                        !string.IsNullOrEmpty(newName = Parser.Settings.GetNewName(argText)))
                    {
                        // yes -- we are going to replace the name, either as a string literal, or by converting
                        // to a member-dot operation.
                        // See if we can't turn it into a dot-operator. If we can't, then we just want to replace the operator with
                        // a new constant wrapper. Otherwise we'll just replace the operator with a new constant wrapper.
                        if (Parser.Settings.IsModificationAllowed(TreeModifications.BracketMemberToDotMember) &&
                            JSScanner.IsSafeIdentifier(newName) &&
                            !JSScanner.IsKeyword(newName))
                        {
                            // the new name is safe to convert to a member-dot operator.
                            // but we don't want to convert the node to the NEW name, because we still need to Analyze the
                            // new member node -- and it might convert the new name to something else. So instead we're
                            // just going to convert this existing string to a member node WITH THE OLD STRING,
                            // and THEN analyze it (which will convert the old string to newName)
                            Member replacementMember = new Member(Context, Parser, m_func, argText);
                            Parent.ReplaceChild(this, replacementMember);

                            // this analyze call will convert the old-name member to the newName value
                            replacementMember.AnalyzeNode();
                            return;
                        }
                        else
                        {
                            // nope; can't convert to a dot-operator.
                            // we're just going to replace the first argument with a new string literal
                            // and continue along our merry way.
                            m_args.ReplaceChild(m_args[0], new ConstantWrapper(newName, PrimitiveType.String, m_args[0].Context, Parser));
                        }
                    }
                    else if (Parser.Settings.IsModificationAllowed(TreeModifications.BracketMemberToDotMember) &&
                             JSScanner.IsSafeIdentifier(argText) &&
                             !JSScanner.IsKeyword(argText))
                    {
                        // not a replacement, but the string literal is a safe identifier. So we will
                        // replace this call node with a Member-dot operation
                        Member replacementMember = new Member(Context, Parser, m_func, argText);
                        Parent.ReplaceChild(this, replacementMember);
                        replacementMember.AnalyzeNode();
                        return;
                    }
                }
            }

            // call the base class to recurse
            base.AnalyzeNode();

            // call this AFTER recursing to give the fields a chance to resolve, because we only
            // want to make this replacement if we are working on the global Date object.
            if (!m_inBrackets && !m_isConstructor &&
                (m_args == null || m_args.Count == 0) &&
                member != null && string.CompareOrdinal(member.Name, "getTime") == 0 &&
                Parser.Settings.IsModificationAllowed(TreeModifications.DateGetTimeToUnaryPlus))
            {
                // this is not a constructor and it's not a brackets call, and there are no arguments.
                // if the function is a member operation to "getTime" and the object of the member is a
                // constructor call to the global "Date" object (not a local), then we want to replace the call
                // with a unary plus on the Date constructor. Converting to numeric type is the same as
                // calling getTime, so it's the equivalent with much fewer bytes.
                CallNode dateConstructor = member.Root as CallNode;
                if (dateConstructor != null &&
                    dateConstructor.IsConstructor)
                {
                    // lookup for the predifined (not local) "Date" field
                    Lookup lookup = dateConstructor.Function as Lookup;
                    if (lookup != null && string.CompareOrdinal(lookup.Name, "Date") == 0 &&
                        lookup.LocalField == null)
                    {
                        // this is in the pattern: (new Date()).getTime()
                        // we want to replace it with +new Date
                        // use the same date constructor node as the operand
                        NumericUnary unary = new NumericUnary(Context, Parser, dateConstructor, JSToken.Plus);

                        // replace us (the call to the getTime method) with this unary operator
                        Parent.ReplaceChild(this, unary);

                        // don't need to AnalyzeNode on the unary operator. The operand has already
                        // been analyzed when we recursed, and the unary operator wouldn't do anything
                        // special anyway (since the operand is not a numeric constant)
                    }
                }
            }
            else if (Parser.Settings.EvalTreatment != EvalTreatment.Ignore)
            {
                // if this is a window.eval call, then we need to mark this scope as unknown just as
                // we would if this was a regular eval call.
                // (unless, of course, the parser settings say evals are safe)
                // call AFTER recursing so we know the left-hand side properties have had a chance to
                // lookup their fields to see if they are local or global
                if (member != null && string.CompareOrdinal(member.Name, "eval") == 0)
                {
                    if (member.LeftHandSide.IsWindowLookup)
                    {
                        // this is a call to window.eval()
                        // mark this scope as unknown so we don't crunch out locals
                        // we might reference in the eval at runtime
                        ScopeStack.Peek().IsKnownAtCompileTime = false;
                    }
                }
                else
                {
                    CallNode callNode = m_func as CallNode;
                    if (callNode != null &&
                        callNode.InBrackets &&
                        callNode.LeftHandSide.IsWindowLookup &&
                        callNode.Arguments.IsSingleConstantArgument("eval"))
                    {
                        // this is a call to window["eval"]
                        // mark this scope as unknown so we don't crunch out locals
                        // we might reference in the eval at runtime
                        ScopeStack.Peek().IsKnownAtCompileTime = false;
                    }
                }
            }

            /* REVIEW: may be too late. lookups may alread have been analyzed and
             * found undefined
             * // check to see if this is an assignment to a window["prop"] structure
             * BinaryOperator binaryOp = Parent as BinaryOperator;
             * if (binaryOp != null && binaryOp.IsAssign
             *  && m_inBrackets
             *  && m_func.IsWindowLookup
             *  && m_args != null)
             * {
             *  // and IF the property is a non-empty constant that isn't currently
             *  // a global field...
             *  string propertyName = m_args.SingleConstantArgument;
             *  if (!string.IsNullOrEmpty(propertyName)
             *      && Parser.GlobalScope[propertyName] == null)
             *  {
             *      // we want to also add it to the global fields so it's not undefined
             *      Parser.GlobalScope.DeclareField(propertyName, null, 0);
             *  }
             * }
             */
        }
Esempio n. 47
0
        private ConstantWrapper LogicalOr(ConstantWrapper left, ConstantWrapper right)
        {
            ConstantWrapper newLiteral = null;
            if (m_parser.Settings.IsModificationAllowed(TreeModifications.EvaluateNumericExpressions))
            {
                try
                {
                    // if the left-hand side evaluates to true, return the left-hand side.
                    // if the left-hand side is false, return the right-hand side.
                    newLiteral = left.ToBoolean() ? left : right;
                }
                catch (InvalidCastException)
                {
                    // if we couldn't cast to bool, ignore
                }
            }

            return newLiteral;
        }
Esempio n. 48
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);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
Esempio n. 49
0
        //---------------------------------------------------------------------------------------
        // ParseIfStatement
        //
        //  IfStatement :
        //    'if' '(' Expression ')' Statement ElseStatement
        //
        //  ElseStatement :
        //    <empty> |
        //    'else' Statement
        //---------------------------------------------------------------------------------------
        private IfNode ParseIfStatement()
        {
            Context ifCtx = m_currentToken.Clone();
            AstNode condition = null;
            AstNode trueBranch = null;
            AstNode falseBranch = null;

            m_blockType.Add(BlockType.Block);
            try
            {
                // parse condition
                GetNextToken();
                m_noSkipTokenSet.Add(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet);
                try
                {
                    if (JSToken.LeftParenthesis != m_currentToken.Token)
                        ReportError(JSError.NoLeftParenthesis);
                    GetNextToken();
                    condition = ParseExpression();

                    // parse statements
                    if (JSToken.RightParenthesis != m_currentToken.Token)
                    {
                        ifCtx.UpdateWith(condition.Context);
                        ReportError(JSError.NoRightParenthesis);
                    }
                    else
                        ifCtx.UpdateWith(m_currentToken);

                    GetNextToken();
                }
                catch (RecoveryTokenException exc)
                {
                    // make up an if condition
                    if (exc._partiallyComputedNode != null)
                        condition = exc._partiallyComputedNode;
                    else
                        condition = new ConstantWrapper(true, PrimitiveType.Boolean, CurrentPositionContext(), this);

                    if (IndexOfToken(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet, exc) == -1)
                    {
                        exc._partiallyComputedNode = null; // really not much to pass up
                        // the if condition was so bogus we do not have a chance to make an If node, give up
                        throw;
                    }
                    else
                    {
                        if (exc._token == JSToken.RightParenthesis)
                            GetNextToken();
                    }
                }
                finally
                {
                    m_noSkipTokenSet.Remove(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet);
                }

                // if this is an assignment, throw a warning in case the developer
                // meant to use == instead of =
                // but no warning if the condition is wrapped in parens. We can know if it's wrapped in parens
                // if the first character of the context is a paren and it's BEFORE the context of the leftmost
                // context of the condition.
                BinaryOperator binOp = condition as BinaryOperator;
                if (binOp != null && binOp.OperatorToken == JSToken.Assign
                    && condition.Context != null && condition.Context.Code != null 
                    && !(condition.Context.Code.StartsWith("(", StringComparison.Ordinal) && condition.Context.IsBefore(binOp.LeftHandSide.Context)))
                {
                    condition.Context.HandleError(JSError.SuspectAssignment);
                }

                m_noSkipTokenSet.Add(NoSkipTokenSet.s_IfBodyNoSkipTokenSet);
                if (JSToken.Semicolon == m_currentToken.Token)
                {
                    ForceReportInfo(JSError.SuspectSemicolon);
                }
                else if (JSToken.LeftCurly != m_currentToken.Token)
                {
                    // if the statements aren't withing curly-braces, throw a possible error
                    ReportError(JSError.StatementBlockExpected, ifCtx, true);
                }

                try
                {
                    // parse a Statement, not a SourceElement
                    trueBranch = ParseStatement(false);
                }
                catch (RecoveryTokenException exc)
                {
                    // make up a block for the if part
                    if (exc._partiallyComputedNode != null)
                        trueBranch = exc._partiallyComputedNode;
                    else
                        trueBranch = new Block(CurrentPositionContext(), this);
                    if (IndexOfToken(NoSkipTokenSet.s_IfBodyNoSkipTokenSet, exc) == -1)
                    {
                        // we have to pass the exception to someone else, make as much as you can from the if
                        exc._partiallyComputedNode = new IfNode(ifCtx, this, condition, trueBranch, falseBranch);
                        throw;
                    }
                }
                finally
                {
                    m_noSkipTokenSet.Remove(NoSkipTokenSet.s_IfBodyNoSkipTokenSet);
                }

                // parse else, if any
                if (JSToken.Else == m_currentToken.Token)
                {
                    Context elseCtx = m_currentToken.Clone();
                    GetNextToken();
                    if (JSToken.Semicolon == m_currentToken.Token)
                        ForceReportInfo(JSError.SuspectSemicolon);
                    // if the statements aren't withing curly-braces, throw a possible error
                    if (JSToken.LeftCurly != m_currentToken.Token
                      && JSToken.If != m_currentToken.Token)
                    {
                        ReportError(JSError.StatementBlockExpected, elseCtx, true);
                    }
                    try
                    {
                        // parse a Statement, not a SourceElement
                        falseBranch = ParseStatement(false);
                    }
                    catch (RecoveryTokenException exc)
                    {
                        // make up a block for the else part
                        if (exc._partiallyComputedNode != null)
                            falseBranch = exc._partiallyComputedNode;
                        else
                            falseBranch = new Block(CurrentPositionContext(), this);
                        exc._partiallyComputedNode = new IfNode(ifCtx, this, condition, trueBranch, falseBranch);
                        throw;
                    }
                }
            }
            finally
            {
                m_blockType.RemoveAt(m_blockType.Count - 1);
            }

            return new IfNode(ifCtx, this, condition, trueBranch, falseBranch);
        }
Esempio n. 50
0
        /// <summary>
        /// Evaluate: CONST [op] (CONST [op] OTHER)
        /// </summary>
        /// <param name="thisConstant">first constant</param>
        /// <param name="otherConstant">second constant</param>
        /// <param name="leftOperator">second operator</param>
        private void EvalToTheRight(BinaryOperator node, ConstantWrapper thisConstant, ConstantWrapper otherConstant, BinaryOperator rightOperator)
        {
            if (node.OperatorToken == JSToken.Plus)
            {
                if (rightOperator.OperatorToken == JSToken.Plus && otherConstant.IsStringLiteral)
                {
                    // plus-plus, and the other constant is a string. So the right operator will be a string-concat
                    // that generates a string. And since this is a plus-operator, then this operator will be a string-
                    // concat as well. So we can just combine the strings now and replace our node with the right-hand
                    // operation
                    ConstantWrapper newLiteral = StringConcat(thisConstant, otherConstant);
                    if (newLiteral != null)
                    {
                        RotateFromRight(node, rightOperator, newLiteral);
                    }
                }
                else if (rightOperator.OperatorToken == JSToken.Minus && !thisConstant.IsStringLiteral)
                {
                    // plus-minus. Now, the minus operation happens first, and it will perform a numeric
                    // operation. The plus is NOT string, so that means it will also be a numeric operation
                    // and we can combine the operators numericly.
                    ConstantWrapper newLiteral = NumericAddition(thisConstant, otherConstant);
                    if (newLiteral != null && NoOverflow(newLiteral))
                    {
                        RotateFromRight(node, rightOperator, newLiteral);
                    }
                    else
                    {
                        ConstantWrapper rightRight = rightOperator.Operand2 as ConstantWrapper;
                        if (rightRight != null)
                        {
                            EvalFarToTheRight(node, thisConstant, rightRight, rightOperator);
                        }
                    }
                }
            }
            else if (node.OperatorToken == JSToken.Minus && rightOperator.OperatorToken == JSToken.Minus)
            {
                // minus-minus
                // both operations are numeric, so we can combine the constant operands. However, we
                // can't combine them into a plus, so make sure we do the minus in the opposite direction
                ConstantWrapper newLiteral = Minus(otherConstant, thisConstant);
                if (newLiteral != null && NoOverflow(newLiteral))
                {
                    rightOperator.SwapOperands();
                    RotateFromLeft(node, rightOperator, newLiteral);
                }
                else
                {
                    ConstantWrapper rightRight = rightOperator.Operand2 as ConstantWrapper;
                    if (rightRight != null)
                    {
                        EvalFarToTheRight(node, thisConstant, rightRight, rightOperator);
                    }
                }
            }
            else if (node.OperatorToken == JSToken.Multiply
                && (rightOperator.OperatorToken == JSToken.Multiply || rightOperator.OperatorToken == JSToken.Divide))
            {
                // multiply-divide or multiply-multiply
                // multiply the operands and use the right-hand operator
                ConstantWrapper newLiteral = Multiply(thisConstant, otherConstant);
                if (newLiteral != null && NoMultiplicativeOverOrUnderFlow(thisConstant, otherConstant, newLiteral))
                {
                    RotateFromRight(node, rightOperator, newLiteral);
                }
            }
            else if (node.OperatorToken == JSToken.Divide)
            {
                if (rightOperator.OperatorToken == JSToken.Multiply)
                {
                    // divide-multiply
                    ConstantWrapper newLiteral = Divide(thisConstant, otherConstant);
                    if (newLiteral != null && NoMultiplicativeOverOrUnderFlow(thisConstant, otherConstant, newLiteral)
                        && newLiteral.ToCode().Length < thisConstant.ToCode().Length + otherConstant.ToCode().Length + 1)
                    {
                        // flip the operator: multiply becomes divide; devide becomes multiply
                        rightOperator.OperatorToken = JSToken.Divide;

                        RotateFromRight(node, rightOperator, newLiteral);
                    }
                }
                else if (rightOperator.OperatorToken == JSToken.Divide)
                {
                    // divide-divide
                    // get constants for left/right and for right/left
                    ConstantWrapper leftOverRight = Divide(thisConstant, otherConstant);
                    ConstantWrapper rightOverLeft = Divide(otherConstant, thisConstant);

                    // get the lengths of the resulting code
                    int leftOverRightLength = leftOverRight != null ? leftOverRight.ToCode().Length : int.MaxValue;
                    int rightOverLeftLength = rightOverLeft != null ? rightOverLeft.ToCode().Length : int.MaxValue;

                    // try whichever is smaller
                    if (leftOverRight != null && NoMultiplicativeOverOrUnderFlow(thisConstant, otherConstant, leftOverRight)
                        && (rightOverLeft == null || leftOverRightLength < rightOverLeftLength))
                    {
                        // use left-over-right.
                        // but only if the resulting value is smaller than the original expression
                        if (leftOverRightLength <= thisConstant.ToCode().Length + otherConstant.ToCode().Length + 1)
                        {
                            // We don't need to swap the operands, but we do need to switch the operator
                            rightOperator.OperatorToken = JSToken.Multiply;
                            RotateFromRight(node, rightOperator, leftOverRight);
                        }
                    }
                    else if (rightOverLeft != null && NoMultiplicativeOverOrUnderFlow(otherConstant, thisConstant, rightOverLeft))
                    {
                        // but only if the resulting value is smaller than the original expression
                        if (rightOverLeftLength <= thisConstant.ToCode().Length + otherConstant.ToCode().Length + 1)
                        {
                            // use right-over-left. Keep the operator, but swap the operands
                            rightOperator.SwapOperands();
                            RotateFromLeft(node, rightOperator, rightOverLeft);
                        }
                    }
                }
            }
        }
Esempio n. 51
0
        //---------------------------------------------------------------------------------------
        // ParseForStatement
        //
        //  ForStatement :
        //    'for' '(' OptionalExpressionNoIn ';' OptionalExpression ';' OptionalExpression ')'
        //    'for' '(' 'var' VariableDeclarationListNoIn ';' OptionalExpression ';' OptionalExpression ')'
        //    'for' '(' LeftHandSideExpression 'in' Expression')'
        //    'for' '(' 'var' Identifier OptionalInitializerNoIn 'in' Expression')'
        //
        //  OptionalExpressionNoIn :
        //    <empty> |
        //    ExpressionNoIn // same as Expression but does not process 'in' as an operator
        //
        //  OptionalInitializerNoIn :
        //    <empty> |
        //    InitializerNoIn // same as initializer but does not process 'in' as an operator
        //---------------------------------------------------------------------------------------
        private AstNode ParseForStatement()
        {
            m_blockType.Add(BlockType.Loop);
            AstNode forNode = null;
            try
            {
                Context forCtx = m_currentToken.Clone();
                GetNextToken();
                if (JSToken.LeftParenthesis != m_currentToken.Token)
                    ReportError(JSError.NoLeftParenthesis);
                GetNextToken();
                bool isForIn = false, recoveryInForIn = false;
                AstNode lhs = null, initializer = null, condOrColl = null, increment = null;

                try
                {
                    if (JSToken.Var == m_currentToken.Token)
                    {
                        isForIn = true;
                        Var varList = new Var(m_currentToken.Clone(), this);
                        varList.Append(ParseIdentifierInitializer(JSToken.In, (FieldAttributes)0));

                        // a list of variable initializers is allowed only in a for(;;)
                        while (JSToken.Comma == m_currentToken.Token)
                        {
                            isForIn = false;
                            varList.Append(ParseIdentifierInitializer(JSToken.In, (FieldAttributes)0));
                            //initializer = new Comma(initializer.context.CombineWith(var.context), initializer, var);
                        }

                        initializer = varList;

                        // if it could still be a for..in, now it's time to get the 'in'
                        if (isForIn)
                        {
                            if (JSToken.In == m_currentToken.Token)
                            {
                                GetNextToken();
                                condOrColl = ParseExpression();
                            }
                            else
                                isForIn = false;
                        }
                    }
                    else
                    {
                        if (JSToken.Semicolon != m_currentToken.Token)
                        {
                            bool isLHS;
                            initializer = ParseUnaryExpression(out isLHS, false);
                            if (isLHS && JSToken.In == m_currentToken.Token)
                            {
                                isForIn = true;
                                lhs = initializer;
                                initializer = null;
                                GetNextToken();
                                m_noSkipTokenSet.Add(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet);
                                try
                                {
                                    condOrColl = ParseExpression();
                                }
                                catch (RecoveryTokenException exc)
                                {
                                    if (IndexOfToken(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet, exc) == -1)
                                    {
                                        exc._partiallyComputedNode = null;
                                        throw;
                                    }
                                    else
                                    {
                                        if (exc._partiallyComputedNode == null)
                                            condOrColl = new ConstantWrapper(true, PrimitiveType.Boolean, CurrentPositionContext(), this); // what could we put here?
                                        else
                                            condOrColl = exc._partiallyComputedNode;
                                    }
                                    if (exc._token == JSToken.RightParenthesis)
                                    {
                                        GetNextToken();
                                        recoveryInForIn = true;
                                    }
                                }
                                finally
                                {
                                    m_noSkipTokenSet.Remove(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet);
                                }
                            }
                            else
                                initializer = ParseExpression(initializer, false, isLHS, JSToken.In);
                        }
                    }
                }
                catch (RecoveryTokenException exc)
                {
                    // error is too early abort for
                    exc._partiallyComputedNode = null;
                    throw;
                }

                // at this point we know whether or not is a for..in
                if (isForIn)
                {
                    if (!recoveryInForIn)
                    {
                        if (JSToken.RightParenthesis != m_currentToken.Token)
                            ReportError(JSError.NoRightParenthesis);
                        forCtx.UpdateWith(m_currentToken);
                        GetNextToken();
                    }
                    AstNode body = null;
                    // if the statements aren't withing curly-braces, throw a possible error
                    if (JSToken.LeftCurly != m_currentToken.Token)
                    {
                        ReportError(JSError.StatementBlockExpected, forCtx, true);
                    }
                    try
                    {
                        // parse a Statement, not a SourceElement
                        body = ParseStatement(false);
                    }
                    catch (RecoveryTokenException exc)
                    {
                        if (exc._partiallyComputedNode == null)
                            body = new Block(CurrentPositionContext(), this);
                        else
                            body = exc._partiallyComputedNode;
                        exc._partiallyComputedNode = new ForIn(forCtx, this, (lhs != null ? lhs : initializer), condOrColl, body);
                        throw;
                    }
                    // for (a in b)
                    //      lhs = a, initializer = null
                    // for (var a in b)
                    //      lhs = null, initializer = var a
                    forNode = new ForIn(forCtx, this, (lhs != null ? lhs : initializer), condOrColl, body);
                }
                else
                {
                    m_noSkipTokenSet.Add(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet);
                    try
                    {
                        if (JSToken.Semicolon != m_currentToken.Token)
                        {
                            ReportError(JSError.NoSemicolon);
                            if (JSToken.Colon == m_currentToken.Token)
                            {
                                m_noSkipTokenSet.Add(NoSkipTokenSet.s_VariableDeclNoSkipTokenSet);
                                try
                                {
                                    SkipTokensAndThrow();
                                }
                                catch (RecoveryTokenException)
                                {
                                    if (JSToken.Semicolon == m_currentToken.Token)
                                        m_errorToken = null;
                                    else
                                        throw;
                                }
                                finally
                                {
                                    m_noSkipTokenSet.Remove(NoSkipTokenSet.s_VariableDeclNoSkipTokenSet);
                                }
                            }
                        }
                        GetNextToken();
                        if (JSToken.Semicolon != m_currentToken.Token)
                        {
                            condOrColl = ParseExpression();
                            if (JSToken.Semicolon != m_currentToken.Token)
                                ReportError(JSError.NoSemicolon);
                        }

                        GetNextToken();
                        if (JSToken.RightParenthesis != m_currentToken.Token)
                            increment = ParseExpression();
                        if (JSToken.RightParenthesis != m_currentToken.Token)
                            ReportError(JSError.NoRightParenthesis);
                        forCtx.UpdateWith(m_currentToken);
                        GetNextToken();
                    }
                    catch (RecoveryTokenException exc)
                    {
                        if (IndexOfToken(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet, exc) == -1)
                        {
                            exc._partiallyComputedNode = null;
                            throw;
                        }
                        else
                        {
                            // discard any partial info, just genrate empty condition and increment and keep going
                            exc._partiallyComputedNode = null;
                            if (condOrColl == null)
                                condOrColl = new ConstantWrapper(true, PrimitiveType.Boolean, CurrentPositionContext(), this);
                        }
                        if (exc._token == JSToken.RightParenthesis)
                        {
                            GetNextToken();
                        }
                    }
                    finally
                    {
                        m_noSkipTokenSet.Remove(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet);
                    }
                    AstNode body = null;
                    // if the statements aren't withing curly-braces, throw a possible error
                    if (JSToken.LeftCurly != m_currentToken.Token)
                    {
                        ReportError(JSError.StatementBlockExpected, forCtx, true);
                    }
                    try
                    {
                        // parse a Statement, not a SourceElement
                        body = ParseStatement(false);
                    }
                    catch (RecoveryTokenException exc)
                    {
                        if (exc._partiallyComputedNode == null)
                            body = new Block(CurrentPositionContext(), this);
                        else
                            body = exc._partiallyComputedNode;
                        exc._partiallyComputedNode = new ForNode(forCtx, this, initializer, condOrColl, increment, body);
                        throw;
                    }
                    forNode = new ForNode(forCtx, this, initializer, condOrColl, increment, body);
                }
            }
            finally
            {
                m_blockType.RemoveAt(m_blockType.Count - 1);
            }

            return forNode;
        }
Esempio n. 52
0
        public override void Visit(Member node)
        {
            if (node != null)
            {
                // if we don't even have any resource strings, then there's nothing
                // we need to do and we can just perform the base operation
                ResourceStrings resourceStrings = m_parser.ResourceStrings;
                if (resourceStrings != null && resourceStrings.Count > 0)
                {
                    // see if the root object is a lookup that corresponds to the
                    // global value (not a local field) for our resource object
                    // (same name)
                    Lookup rootLookup = node.Root as Lookup;
                    if (rootLookup != null
                        && rootLookup.LocalField == null
                        && string.CompareOrdinal(rootLookup.Name, resourceStrings.Name) == 0)
                    {
                        // it is -- we're going to replace this with a string value.
                        // if this member name is a string on the object, we'll replacve it with
                        // the literal. Otherwise we'll replace it with an empty string.
                        // see if the string resource contains this value
                        ConstantWrapper stringLiteral = new ConstantWrapper(
                            resourceStrings[node.Name] ?? string.Empty,
                            PrimitiveType.String,
                            node.Context,
                            m_parser
                            );

                        node.Parent.ReplaceChild(node, stringLiteral);

                        // analyze the literal
                        stringLiteral.Accept(this);
                        return;
                    }
                }

                // if we are replacing property names and we have something to replace
                if (m_parser.Settings.HasRenamePairs && m_parser.Settings.ManualRenamesProperties
                    && m_parser.Settings.IsModificationAllowed(TreeModifications.PropertyRenaming))
                {
                    // see if this name is a target for replacement
                    string newName = m_parser.Settings.GetNewName(node.Name);
                    if (!string.IsNullOrEmpty(newName))
                    {
                        // it is -- set the name to the new name
                        node.Name = newName;
                    }
                }

                // check the name of the member for reserved words that aren't allowed
                if (JSScanner.IsKeyword(node.Name, ScopeStack.Peek().UseStrict))
                {
                    node.NameContext.HandleError(JSError.KeywordUsedAsIdentifier, true);
                }

                // recurse
                base.Visit(node);
            }
        }
Esempio n. 53
0
        private ConstantWrapper BitwiseXor(ConstantWrapper left, ConstantWrapper right)
        {
            ConstantWrapper newLiteral = null;

            if (m_parser.Settings.IsModificationAllowed(TreeModifications.EvaluateNumericExpressions))
            {
                try
                {
                    Int32 lValue = left.ToInt32();
                    Int32 rValue = right.ToInt32();
                    newLiteral = new ConstantWrapper(Convert.ToDouble(lValue ^ rValue), PrimitiveType.Number, 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;
        }
Esempio n. 54
0
 public void Visit(ConstantWrapper node)
 {
     // it's a constant, so we don't care
 }
Esempio n. 55
0
        public override void Visit(CallNode node)
        {
            if (node != null)
            {
                // see if this is a member (we'll need it for a couple checks)
                Member member = node.Function as Member;

                if (m_parser.Settings.StripDebugStatements
                    && m_parser.Settings.IsModificationAllowed(TreeModifications.StripDebugStatements))
                {
                    // if this is a member, and it's a debugger object, and it's a constructor....
                    if (member != null && member.IsDebuggerStatement && node.IsConstructor)
                    {
                        // we need to replace our debugger object with a generic Object
                        node.ReplaceChild(node.Function, new Lookup("Object", node.Function.Context, m_parser));

                        // and make sure the node list is empty
                        if (node.Arguments != null && node.Arguments.Count > 0)
                        {
                            node.ReplaceChild(node.Arguments, new AstNodeList(node.Arguments.Context, m_parser));
                        }
                    }
                }

                // if this is a constructor and we want to collapse
                // some of them to literals...
                if (node.IsConstructor && m_parser.Settings.CollapseToLiteral)
                {
                    // see if this is a lookup, and if so, if it's pointing to one
                    // of the two constructors we want to collapse
                    Lookup lookup = node.Function as Lookup;
                    if (lookup != null)
                    {
                        if (lookup.Name == "Object"
                            && m_parser.Settings.IsModificationAllowed(TreeModifications.NewObjectToObjectLiteral))
                        {
                            // no arguments -- the Object constructor with no arguments is the exact same as an empty
                            // object literal
                            if (node.Arguments == null || node.Arguments.Count == 0)
                            {
                                // replace our node with an object literal
                                ObjectLiteral objLiteral = new ObjectLiteral(node.Context, m_parser, null, null);
                                if (node.Parent.ReplaceChild(node, objLiteral))
                                {
                                    // and bail now. No need to recurse -- it's an empty literal
                                    return;
                                }
                            }
                            else if (node.Arguments.Count == 1)
                            {
                                // one argument
                                // check to see if it's an object literal.
                                ObjectLiteral objectLiteral = node.Arguments[0] as ObjectLiteral;
                                if (objectLiteral != null)
                                {
                                    // the Object constructor with an argument that is a JavaScript object merely returns the
                                    // argument. Since the argument is an object literal, it is by definition a JavaScript object
                                    // and therefore we can replace the constructor call with the object literal
                                    node.Parent.ReplaceChild(node, objectLiteral);

                                    // don't forget to recurse the object now
                                    objectLiteral.Accept(this);

                                    // and then bail -- we don't want to process this call
                                    // operation any more; we've gotten rid of it
                                    return;
                                }
                            }
                        }
                        else if (lookup.Name == "Array"
                            && m_parser.Settings.IsModificationAllowed(TreeModifications.NewArrayToArrayLiteral))
                        {
                            // Array is trickier.
                            // If there are no arguments, then just use [].
                            // if there are multiple arguments, then use [arg0,arg1...argN].
                            // but if there is one argument and it's numeric, we can't crunch it.
                            // also can't crunch if it's a function call or a member or something, since we won't
                            // KNOW whether or not it's numeric.
                            //
                            // so first see if it even is a single-argument constant wrapper.
                            ConstantWrapper constWrapper = (node.Arguments != null && node.Arguments.Count == 1
                                ? node.Arguments[0] as ConstantWrapper
                                : null);

                            // if the argument count is not one, then we crunch.
                            // if the argument count IS one, we only crunch if we have a constant wrapper,
                            // AND it's not numeric.
                            if (node.Arguments == null
                              || node.Arguments.Count != 1
                              || (constWrapper != null && !constWrapper.IsNumericLiteral))
                            {
                                // create the new array literal object
                                ArrayLiteral arrayLiteral = new ArrayLiteral(node.Context, m_parser, node.Arguments);

                                // replace ourself within our parent
                                if (node.Parent.ReplaceChild(node, arrayLiteral))
                                {
                                    // recurse
                                    arrayLiteral.Accept(this);
                                    // and bail -- we don't want to recurse this node any more
                                    return;
                                }
                            }
                        }
                    }
                }

                // if we are replacing resource references with strings generated from resource files
                // and this is a brackets call: lookup[args]
                ResourceStrings resourceStrings = m_parser.ResourceStrings;
                if (node.InBrackets && resourceStrings != null && resourceStrings.Count > 0)
                {
                    // see if the root object is a lookup that corresponds to the
                    // global value (not a local field) for our resource object
                    // (same name)
                    Lookup rootLookup = node.Function as Lookup;
                    if (rootLookup != null
                        && rootLookup.LocalField == null
                        && string.CompareOrdinal(rootLookup.Name, resourceStrings.Name) == 0)
                    {
                        // we're going to replace this node with a string constant wrapper
                        // but first we need to make sure that this is a valid lookup.
                        // if the parameter contains anything that would vary at run-time,
                        // then we need to throw an error.
                        // the parser will always have either one or zero nodes in the arguments
                        // arg list. We're not interested in zero args, so just make sure there is one
                        if (node.Arguments.Count == 1)
                        {
                            // must be a constant wrapper
                            ConstantWrapper argConstant = node.Arguments[0] as ConstantWrapper;
                            if (argConstant != null)
                            {
                                string resourceName = argConstant.Value.ToString();

                                // get the localized string from the resources object
                                ConstantWrapper resourceLiteral = new ConstantWrapper(
                                    resourceStrings[resourceName],
                                    PrimitiveType.String,
                                    node.Context,
                                    m_parser);

                                // replace this node with localized string, analyze it, and bail
                                // so we don't anaylze the tree we just replaced
                                node.Parent.ReplaceChild(node, resourceLiteral);
                                resourceLiteral.Accept(this);
                                return;
                            }
                            else
                            {
                                // error! must be a constant
                                node.Context.HandleError(
                                    JSError.ResourceReferenceMustBeConstant,
                                    true);
                            }
                        }
                        else
                        {
                            // error! can only be a single constant argument to the string resource object.
                            // the parser will only have zero or one arguments, so this must be zero
                            // (since the parser won't pass multiple args to a [] operator)
                            node.Context.HandleError(
                                JSError.ResourceReferenceMustBeConstant,
                                true);
                        }
                    }
                }

                // and finally, if this is a backets call and the argument is a constantwrapper that can
                // be an identifier, just change us to a member node:  obj["prop"] to obj.prop.
                // but ONLY if the string value is "safe" to be an identifier. Even though the ECMA-262
                // spec says certain Unicode categories are okay, in practice the various major browsers
                // all seem to have problems with certain characters in identifiers. Rather than risking
                // some browsers breaking when we change this syntax, don't do it for those "danger" categories.
                if (node.InBrackets && node.Arguments != null)
                {
                    // see if there is a single, constant argument
                    string argText = node.Arguments.SingleConstantArgument;
                    if (argText != null)
                    {
                        // see if we want to replace the name
                        string newName;
                        if (m_parser.Settings.HasRenamePairs && m_parser.Settings.ManualRenamesProperties
                            && m_parser.Settings.IsModificationAllowed(TreeModifications.PropertyRenaming)
                            && !string.IsNullOrEmpty(newName = m_parser.Settings.GetNewName(argText)))
                        {
                            // yes -- we are going to replace the name, either as a string literal, or by converting
                            // to a member-dot operation.
                            // See if we can't turn it into a dot-operator. If we can't, then we just want to replace the operator with
                            // a new constant wrapper. Otherwise we'll just replace the operator with a new constant wrapper.
                            if (m_parser.Settings.IsModificationAllowed(TreeModifications.BracketMemberToDotMember)
                                && JSScanner.IsSafeIdentifier(newName)
                                && !JSScanner.IsKeyword(newName, node.EnclosingScope.UseStrict))
                            {
                                // the new name is safe to convert to a member-dot operator.
                                // but we don't want to convert the node to the NEW name, because we still need to Analyze the
                                // new member node -- and it might convert the new name to something else. So instead we're
                                // just going to convert this existing string to a member node WITH THE OLD STRING,
                                // and THEN analyze it (which will convert the old string to newName)
                                Member replacementMember = new Member(node.Context, m_parser, node.Function, argText, node.Arguments[0].Context);
                                node.Parent.ReplaceChild(node, replacementMember);

                                // this analyze call will convert the old-name member to the newName value
                                replacementMember.Accept(this);
                                return;
                            }
                            else
                            {
                                // nope; can't convert to a dot-operator.
                                // we're just going to replace the first argument with a new string literal
                                // and continue along our merry way.
                                node.Arguments.ReplaceChild(node.Arguments[0], new ConstantWrapper(newName, PrimitiveType.String, node.Arguments[0].Context, m_parser));
                            }
                        }
                        else if (m_parser.Settings.IsModificationAllowed(TreeModifications.BracketMemberToDotMember)
                            && JSScanner.IsSafeIdentifier(argText)
                            && !JSScanner.IsKeyword(argText, node.EnclosingScope.UseStrict))
                        {
                            // not a replacement, but the string literal is a safe identifier. So we will
                            // replace this call node with a Member-dot operation
                            Member replacementMember = new Member(node.Context, m_parser, node.Function, argText, node.Arguments[0].Context);
                            node.Parent.ReplaceChild(node, replacementMember);
                            replacementMember.Accept(this);
                            return;
                        }
                    }
                }

                // call the base class to recurse
                base.Visit(node);

                // might have changed
                member = node.Function as Member;

                // call this AFTER recursing to give the fields a chance to resolve, because we only
                // want to make this replacement if we are working on the global Date object.
                if (!node.InBrackets && !node.IsConstructor
                    && (node.Arguments == null || node.Arguments.Count == 0)
                    && member != null && string.CompareOrdinal(member.Name, "getTime") == 0
                    && m_parser.Settings.IsModificationAllowed(TreeModifications.DateGetTimeToUnaryPlus))
                {
                    // this is not a constructor and it's not a brackets call, and there are no arguments.
                    // if the function is a member operation to "getTime" and the object of the member is a
                    // constructor call to the global "Date" object (not a local), then we want to replace the call
                    // with a unary plus on the Date constructor. Converting to numeric type is the same as
                    // calling getTime, so it's the equivalent with much fewer bytes.
                    CallNode dateConstructor = member.Root as CallNode;
                    if (dateConstructor != null
                        && dateConstructor.IsConstructor)
                    {
                        // lookup for the predifined (not local) "Date" field
                        Lookup lookup = dateConstructor.Function as Lookup;
                        if (lookup != null && string.CompareOrdinal(lookup.Name, "Date") == 0
                            && lookup.LocalField == null)
                        {
                            // this is in the pattern: (new Date()).getTime()
                            // we want to replace it with +new Date
                            // use the same date constructor node as the operand
                            NumericUnary unary = new NumericUnary(node.Context, m_parser, dateConstructor, JSToken.Plus);

                            // replace us (the call to the getTime method) with this unary operator
                            node.Parent.ReplaceChild(node, unary);

                            // don't need to recurse on the unary operator. The operand has already
                            // been analyzed when we recursed, and the unary operator wouldn't do anything
                            // special anyway (since the operand is not a numeric constant)
                        }
                    }
                }
                else
                {
                    var isEval = false;

                    var lookup = node.Function as Lookup;
                    if (lookup != null
                        && string.CompareOrdinal(lookup.Name, "eval") == 0
                        && lookup.VariableField is JSPredefinedField)
                    {
                        // call to predefined eval function
                        isEval = true;
                    }
                    else if (member != null && string.CompareOrdinal(member.Name, "eval") == 0)
                    {
                        // if this is a window.eval call, then we need to mark this scope as unknown just as
                        // we would if this was a regular eval call.
                        // (unless, of course, the parser settings say evals are safe)
                        // call AFTER recursing so we know the left-hand side properties have had a chance to
                        // lookup their fields to see if they are local or global
                        if (member.LeftHandSide.IsWindowLookup)
                        {
                            // this is a call to window.eval()
                            isEval = true;
                        }
                    }
                    else
                    {
                        CallNode callNode = node.Function as CallNode;
                        if (callNode != null
                            && callNode.InBrackets
                            && callNode.LeftHandSide.IsWindowLookup
                            && callNode.Arguments.IsSingleConstantArgument("eval"))
                        {
                            // this is a call to window["eval"]
                            isEval = true;
                        }
                    }

                    if (isEval)
                    {
                        if (m_parser.Settings.EvalTreatment != EvalTreatment.Ignore)
                        {
                            // mark this scope as unknown so we don't crunch out locals
                            // we might reference in the eval at runtime
                            ScopeStack.Peek().IsKnownAtCompileTime = false;
                        }
                    }
                }
            }
        }