Example #1
0
        public override void Visit(Var node)
        {
            if (node != null)
            {
                // don't bother creating a list of var-statements if we're not going to move them
                if (m_moveVarStatements)
                {
                    if (m_varStatements == null)
                    {
                        m_varStatements = new List<Var>();
                    }

                    // add the node to the list of variable declarations
                    m_varStatements.Add(node);
                }

                // and recurse
                base.Visit(node);
            }
        }
Example #2
0
        private static int RelocateVar(Block block, int insertAt, Var varStatement)
        {
            // if the var statement is at the next position to insert, then we don't need
            // to do anything.
            if (block[insertAt] != varStatement && !InsideConditionalComment(varStatement))
            {
                // check to see if the current position is a var and we are the NEXT statement.
                // if that's the case, we don't need to break out the initializer, just append all the
                // vardecls as-is to the current position.
                var existingVar = block[insertAt] as Var;
                if (existingVar != null && block[insertAt + 1] == varStatement)
                {
                    // just append our vardecls to the insertion point, then delete our statement
                    existingVar.Append(varStatement);
                    block.RemoveAt(insertAt + 1);
                }
                else
                {
                    // iterate through the decls and count how many have initializers
                    var initializerCount = 0;
                    for (var ndx = 0; ndx < varStatement.Count; ++ndx)
                    {
                        if (varStatement[ndx].Initializer != null)
                        {
                            ++initializerCount;
                        }
                    }

                    // if there are more than two decls with initializers, then we won't actually
                    // be gaining anything by moving the var to the top. We'll get rid of the four
                    // bytes for the "var ", but we'll be adding two bytes for the name and comma
                    // because name=init will still need to remain behind.
                    if (initializerCount <= 2)
                    {
                        // first iterate through all the declarations in the var statement,
                        // constructing an expression statement that is made up of assignment
                        // operators for each of the declarations that have initializers (if any)
                        // and removing all the initializers
                        var assignments = new List<AstNode>();
                        for (var ndx = 0; ndx < varStatement.Count; ++ndx)
                        {
                            var varDecl = varStatement[ndx];
                            if (varDecl.Initializer != null)
                            {
                                if (varDecl.IsCCSpecialCase)
                                {
                                    // create a vardecl with the same name and no initializer
                                    var copyDecl = new VariableDeclaration(
                                        varDecl.Context,
                                        varDecl.Parser,
                                        varDecl.Identifier,
                                        varDecl.Field.OriginalContext,
                                        null,
                                        0,
                                        true);

                                    // replace the special vardecl with the copy
                                    varStatement.ReplaceChild(varDecl, copyDecl);

                                    // add the original vardecl to the list of "assignments"
                                    assignments.Add(varDecl);
                                }
                                else
                                {
                                    // hold on to the object so we don't lose it to the GC
                                    var initializer = varDecl.Initializer;

                                    // remove it from the vardecl
                                    varDecl.ReplaceChild(initializer, null);

                                    // create an assignment operator for a lookup to the name
                                    // as the left, and the initializer as the right, and add it to the list
                                    assignments.Add(new BinaryOperator(
                                        varDecl.Context,
                                        varDecl.Parser,
                                        new Lookup(varDecl.Identifier, varDecl.Field.OriginalContext, varDecl.Parser),
                                        initializer,
                                        JSToken.Assign));
                                }
                            }
                        }

                        // now if there were any initializers...
                        if (assignments.Count > 0)
                        {
                            // we want to create one big expression from all the assignments and replace the
                            // var statement with the assignment(s) expression. Start at position n=1 and create
                            // a binary operator of n-1 as the left, n as the right, and using a comma operator.
                            var expression = assignments[0];
                            for (var ndx = 1; ndx < assignments.Count; ++ndx)
                            {
                                expression = new BinaryOperator(
                                    null,
                                    expression.Parser,
                                    expression,
                                    assignments[ndx],
                                    JSToken.Comma);
                            }

                            // replace the var with the expression.
                            // we still have a pointer to the var, so we can insert it back into the proper
                            // place next.
                            varStatement.Parent.ReplaceChild(varStatement, expression);
                        }
                        else
                        {
                            // no initializers.
                            // if the parent is a for-in statement...
                            var forInParent = varStatement.Parent as ForIn;
                            if (forInParent != null)
                            {
                                // we want to replace the var statement with a lookup for the var
                                // there should be only one vardecl
                                var varDecl = varStatement[0];
                                varStatement.Parent.ReplaceChild(
                                    varStatement,
                                    new Lookup(varDecl.Identifier, varDecl.Field.OriginalContext, varStatement.Parser));
                            }
                            else
                            {
                                // just remove the var statement altogether
                                varStatement.Parent.ReplaceChild(varStatement, null);
                            }
                        }

                        // if the statement at the insertion point is a var-statement already,
                        // then we just need to append our vardecls to it. Otherwise we'll insert our
                        // var statement at the right point
                        if (existingVar != null)
                        {
                            // append the varstatement we want to move to the existing var, which will
                            // transfer all the vardecls to it.
                            existingVar.Append(varStatement);
                        }
                        else
                        {
                            // move the var to the insert point, incrementing the position or next time
                            block.Insert(insertAt, varStatement);
                        }
                    }
                }
            }

            return insertAt;
        }
Example #3
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;
        }
Example #4
0
        //---------------------------------------------------------------------------------------
        // ParseVariableStatement
        //
        //  VariableStatement :
        //    'var' VariableDeclarationList
        //
        //  VariableDeclarationList :
        //    VariableDeclaration |
        //    VariableDeclaration ',' VariableDeclarationList
        //
        //  VariableDeclaration :
        //    Identifier Initializer
        //
        //  Initializer :
        //    <empty> |
        //    '=' AssignmentExpression
        //---------------------------------------------------------------------------------------
        private AstNode ParseVariableStatement(FieldAttributes visibility)
        {
            Var varList = new Var(m_currentToken.Clone(), this);
            bool single = true;
            AstNode vdecl = null;
            AstNode identInit = null;

            for (; ; )
            {
                m_noSkipTokenSet.Add(NoSkipTokenSet.s_EndOfLineToken);
                try
                {
                    identInit = ParseIdentifierInitializer(JSToken.None, visibility);
                }
                catch (RecoveryTokenException exc)
                {
                    // an exception is passing by, possibly bringing some info, save the info if any
                    if (exc._partiallyComputedNode != null)
                    {
                        if (!single)
                        {
                            varList.Append(exc._partiallyComputedNode);
                            varList.Context.UpdateWith(exc._partiallyComputedNode.Context);
                            exc._partiallyComputedNode = varList;
                        }
                    }
                    if (IndexOfToken(NoSkipTokenSet.s_EndOfLineToken, exc) == -1)
                        throw;
                    else
                    {
                        if (single)
                            identInit = exc._partiallyComputedNode;
                    }
                }
                finally
                {
                    m_noSkipTokenSet.Remove(NoSkipTokenSet.s_EndOfLineToken);
                }

                if (identInit != null)
                {
                    vdecl = identInit;
                    varList.Append(vdecl);
                }

                if (JSToken.Semicolon == m_currentToken.Token
                    || JSToken.RightCurly == m_currentToken.Token)
                {
                    if (JSToken.Semicolon == m_currentToken.Token)
                    {
                        vdecl.Context.UpdateWith(m_currentToken);
                        GetNextToken();
                    }
                    break;
                }
                
                if (JSToken.Comma == m_currentToken.Token)
                {
                    single = false;
                    continue;
                }
                
                if (m_scanner.GotEndOfLine)
                {
                    break;
                }

                // assume the variable statement was terminated and move on
                ReportError(JSError.NoSemicolon, true);
                break;
            }

            if (vdecl != null)
            {
                varList.Context.UpdateWith(vdecl.Context);
            }
            return varList;
        }
Example #5
0
 private static bool VarDeclExists(Var node, int ndx, string name)
 {
     // only need to look forward from the index passed
     for (; ndx < node.Count; ++ndx)
     {
         // string must be exact match
         if (string.CompareOrdinal(node[ndx].Identifier, name) == 0)
         {
             // there is at least one -- we can bail
             return true;
         }
     }
     // if we got here, we didn't find any matches
     return false;
 }
Example #6
0
 private static void DeleteNoInits(Var node, int min, string name)
 {
     // walk backwards from the end of the list down to (and including) the minimum index
     for (int ndx = node.Count - 1; ndx >= min; --ndx)
     {
         // if the name matches and there is no initializer...
         if (string.CompareOrdinal(node[ndx].Identifier, name) == 0
             && node[ndx].Initializer == null)
         {
             // ...remove it from the list
             node.RemoveAt(ndx);
         }
     }
 }
Example #7
0
        private static bool AreAssignmentsInVar(BinaryOperator binaryOp, Var varStatement)
        {
            bool areAssignmentsInVar = false;

            if (binaryOp != null)
            {
                // we only want to pop positive for the simple assign (=). If it's any of the
                // complex assigns (+=, -=, etc) then we don't want to combine them.
                if (binaryOp.OperatorToken == JSToken.Assign)
                {
                    // see if the left-hand side is a simple lookup
                    Lookup lookup = binaryOp.Operand1 as Lookup;
                    if (lookup != null)
                    {
                        // it is. see if that variable is in the previous var statement
                        areAssignmentsInVar = varStatement.Contains(lookup.Name);
                    }
                }
                else if (binaryOp.OperatorToken == JSToken.Comma)
                {
                    // this is a comma operator, so we will return true only if both
                    // left and right operators are assignments to vars defined in the
                    // var statement
                    areAssignmentsInVar = AreAssignmentsInVar(binaryOp.Operand1 as BinaryOperator, varStatement)
                        && AreAssignmentsInVar(binaryOp.Operand2 as BinaryOperator, varStatement);
                }
            }

            return areAssignmentsInVar;
        }
Example #8
0
        public override void Visit(Var node)
        {
            if (node != null)
            {
                // first we want to weed out duplicates that don't have initializers
                // var a=1, a=2 is okay, but var a, a=2 and var a=2, a should both be just var a=2,
                // and var a, a should just be var a
                if (m_parser.Settings.IsModificationAllowed(TreeModifications.RemoveDuplicateVar))
                {
                    // first we want to weed out duplicates that don't have initializers
                    // var a=1, a=2 is okay, but var a, a=2 and var a=2, a should both be just var a=2,
                    // and var a, a should just be var a
                    int ndx = 0;
                    while (ndx < node.Count)
                    {
                        string thisName = node[ndx].Identifier;

                        // handle differently if we have an initializer or not
                        if (node[ndx].Initializer != null)
                        {
                            // the current vardecl has an initializer, so we want to delete any other
                            // vardecls of the same name in the rest of the list with no initializer
                            // and move on to the next item afterwards
                            DeleteNoInits(node, ++ndx, thisName);
                        }
                        else
                        {
                            // this vardecl has no initializer, so we can delete it if there is ANY
                            // other vardecl with the same name (whether or not it has an initializer)
                            if (VarDeclExists(node, ndx + 1, thisName))
                            {
                                node.RemoveAt(ndx);

                                // don't increment the index; we just deleted the current item,
                                // so the next item just slid into this position
                            }
                            else
                            {
                                // nope -- it's the only one. Move on to the next
                                ++ndx;
                            }
                        }
                    }
                }

                // recurse the analyze
                base.Visit(node);
            }
        }
Example #9
0
        internal void AddGeneratedVar(string name, AstNode initializer, bool isLiteral)
        {
            // if the body is empty, create one now
            if (Body == null)
            {
                Body = new Block(null, Parser);
            }

            // see if the first statement in the body (if any) is a var already
            Var var = null;
            if (Body.Count > 0)
            {
                var = Body[0] as Var;
            }

            VariableDeclaration varDecl = new VariableDeclaration(
                null,
                Parser,
                name,
                new Context(Parser),
                initializer,
                (isLiteral ? FieldAttributes.Literal : 0)
                );
            varDecl.IsGenerated = true;

            // make sure we set the crunchability of this field to TRUE. Doesn't matter
            // whether it's a global or within a with-scope or what-have-you. It didn't
            // exist in the sources (we are generating it now) so we can rename it whatever
            // the heck we want.
            varDecl.Field.CanCrunch = true;

            if (var != null)
            {
                // the first statement is a var; just add a new declaration to the front
                var.InsertAt(0, varDecl);
            }
            else
            {
                // not a var; create a new one
                var = new Var(null, Parser);
                var.Append(varDecl);
                Body.Insert(0, var);
            }
        }