Пример #1
0
        private static int RelocateFunction(JsBlock block, int insertAt, JsFunctionObject funcDecl)
        {
            if (block[insertAt] != funcDecl)
            {
                // technically function declarations can only be direct children of the program or a function block.
                // and since we are passing in such a block, the parent of the function declaration better be that
                // block. If it isn't, we don't want to move it because it's not in an allowed place, and different
                // browsers treat that situation differently. Some browsers would process such funcdecls as if
                // they were a direct child of the main block. Others will treat it like a function expression with
                // an external name, and only assign the function to the name if that line of code is actually
                // executed. So since there's a difference, just leave them as-is and only move valid funcdecls.
                if (funcDecl.Parent == block)
                {
                    // remove the function from it's parent, which will take it away from where it is right now.
                    funcDecl.Parent.ReplaceChild(funcDecl, null);

                    // now insert it into the block at the new location, incrementing the location so the next function
                    // will be inserted after it. It is important that they be in the same order as the source, or the semantics
                    // will change when there are functions with the same name.
                    block.Insert(insertAt++, funcDecl);
                }
            }
            else
            {
                // we're already in the right place. Just increment the pointer to move to the next position
                // for next time
                ++insertAt;
            }

            // return the new position
            return(insertAt);
        }
        private void PossiblyBreakExpressionList(JsBinaryOperator node, JsBlock parentBlock, JsAstNodeList nodeList)
        {
            // if the first item can be broken, then we an break it and be done.
            // otherwise we're going to have to walk until we find a breaking place
            if (CanBeBroken(nodeList[0]))
            {
                // break the first item. insert the left-hand side at our position and
                // recurse it. Then rotate the node.
                var index = parentBlock.IndexOf(node);
                var temp  = node.Operand1;
                RotateOpeator(node, nodeList);
                parentBlock.Insert(index, temp);

                // assumes nothing will cause the node to be deleted, because then it
                // would cause us to miss the following item
                temp.Accept(this);
            }
            else
            {
                // the first one can't be broken, so find the first one that can (if any)
                for (var ndx = 1; ndx < nodeList.Count; ++ndx)
                {
                    if (CanBeBroken(nodeList[ndx]))
                    {
                        if (ndx == 1)
                        {
                            // the second item is where we are breaking it, so we're going to pull
                            // the first item, replace the list with that first item, then insert
                            // a new comma operator after the current node
                            var temp = nodeList[0];
                            nodeList.RemoveAt(0);
                            node.Operand2 = temp;

                            // if there's nothing left, then let it die. Otherwise split off
                            // the remainder and insert after the current item.
                            if (nodeList.Count > 0)
                            {
                                parentBlock.InsertAfter(node, CreateSplitNodeFromEnd(nodeList, 0));
                            }
                        }
                        else
                        {
                            // split off items from the index where we want to split, and insert
                            // it after the current node and leave the node list where it is.
                            parentBlock.InsertAfter(node, CreateSplitNodeFromEnd(nodeList, ndx));
                        }

                        // and now that we've broken it, bail.
                        break;
                    }
                }

                // regardless if anything changed, recurse this node now
                base.Visit(node);
            }
        }
Пример #3
0
        private static int RelocateDirectivePrologue(JsBlock block, int insertAt, JsDirectivePrologue directivePrologue)
        {
            // skip over any important comments
            while (insertAt < block.Count && (block[insertAt] is JsImportantComment))
            {
                ++insertAt;
            }

            // if the one we want to insert is already at this spot, then we're good to go
            if (block[insertAt] != directivePrologue)
            {
                // remove it from where it is right now and insert it into the proper location
                directivePrologue.Parent.ReplaceChild(directivePrologue, null);
                block.Insert(insertAt, directivePrologue);
            }

            // and move up to the next slot
            return(++insertAt);
        }
Пример #4
0
        private static int RelocateVar(JsBlock block, int insertAt, JsVar varStatement)
        {
            // if the var statement is at the next position to insert, then we don't need
            // to do anything.
            if (block[insertAt] != 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 JsVar;
                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 <JsAstNode>();
                        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 JsVariableDeclaration(varDecl.Context, varDecl.Parser)
                                    {
                                        Identifier    = varDecl.Identifier,
                                        NameContext   = varDecl.VariableField.OriginalContext,
                                        VariableField = varDecl.VariableField
                                    };

                                    // replace the special vardecl with the copy
                                    varStatement[ndx] = copyDecl;

                                    // add the original vardecl to the list of "assignments"
                                    assignments.Add(varDecl);

                                    // add the new decl to the field's declaration list, and remove the old one
                                    // because we're going to change that to an assignment.
                                    varDecl.VariableField.Declarations.Add(copyDecl);
                                    varDecl.VariableField.Declarations.Remove(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.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
                                    var lookup = new JsLookup(varDecl.VariableField.OriginalContext, varDecl.Parser)
                                    {
                                        Name          = varDecl.Identifier,
                                        VariableField = varDecl.VariableField,
                                    };
                                    assignments.Add(new JsBinaryOperator(varDecl.Context, varDecl.Parser)
                                    {
                                        Operand1        = lookup,
                                        Operand2        = initializer,
                                        OperatorToken   = JsToken.Assign,
                                        OperatorContext = varDecl.AssignContext
                                    });

                                    // add the new lookup to the field's references
                                    varDecl.VariableField.References.Add(lookup);
                                }
                            }
                        }

                        // 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 = JsCommaOperator.CombineWithComma(null, expression.Parser, expression, assignments[ndx]);
                            }

                            // 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 JsForIn;
                            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];
                                var lookup  = new JsLookup(varDecl.VariableField.OriginalContext, varStatement.Parser)
                                {
                                    Name          = varDecl.Identifier,
                                    VariableField = varDecl.VariableField
                                };
                                varStatement.Parent.ReplaceChild(varStatement, lookup);
                                varDecl.VariableField.References.Add(lookup);
                            }
                            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);
        }
        private static int RelocateVar(JsBlock block, int insertAt, JsVar varStatement)
        {
            // if the var statement is at the next position to insert, then we don't need
            // to do anything.
            if (block[insertAt] != 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 JsVar;
                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<JsAstNode>();
                        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 JsVariableDeclaration(varDecl.Context, varDecl.Parser)
                                        {
                                            Identifier = varDecl.Identifier,
                                            NameContext = varDecl.VariableField.OriginalContext,
                                            VariableField = varDecl.VariableField
                                        };

                                    // replace the special vardecl with the copy
                                    varStatement[ndx] = copyDecl;

                                    // add the original vardecl to the list of "assignments"
                                    assignments.Add(varDecl);

                                    // add the new decl to the field's declaration list, and remove the old one
                                    // because we're going to change that to an assignment.
                                    varDecl.VariableField.Declarations.Add(copyDecl);
                                    varDecl.VariableField.Declarations.Remove(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.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
                                    var lookup = new JsLookup(varDecl.VariableField.OriginalContext, varDecl.Parser)
                                        {
                                            Name = varDecl.Identifier,
                                            VariableField = varDecl.VariableField,
                                        };
                                    assignments.Add(new JsBinaryOperator(varDecl.Context, varDecl.Parser)
                                        {
                                            Operand1 = lookup,
                                            Operand2 = initializer,
                                            OperatorToken = JsToken.Assign,
                                            OperatorContext = varDecl.AssignContext
                                        });

                                    // add the new lookup to the field's references
                                    varDecl.VariableField.References.Add(lookup);
                                }
                            }
                        }

                        // 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 = JsCommaOperator.CombineWithComma(null, expression.Parser, expression, assignments[ndx]);
                            }

                            // 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 JsForIn;
                            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];
                                var lookup = new JsLookup(varDecl.VariableField.OriginalContext, varStatement.Parser)
                                    {
                                        Name = varDecl.Identifier,
                                        VariableField = varDecl.VariableField
                                    };
                                varStatement.Parent.ReplaceChild(varStatement, lookup);
                                varDecl.VariableField.References.Add(lookup);
                            }
                            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;
        }
        private static int RelocateFunction(JsBlock block, int insertAt, JsFunctionObject funcDecl)
        {
            if (block[insertAt] != funcDecl)
            {
                // technically function declarations can only be direct children of the program or a function block.
                // and since we are passing in such a block, the parent of the function declaration better be that
                // block. If it isn't, we don't want to move it because it's not in an allowed place, and different
                // browsers treat that situation differently. Some browsers would process such funcdecls as if
                // they were a direct child of the main block. Others will treat it like a function expression with
                // an external name, and only assign the function to the name if that line of code is actually
                // executed. So since there's a difference, just leave them as-is and only move valid funcdecls.
                if (funcDecl.Parent == block)
                {
                    // remove the function from it's parent, which will take it away from where it is right now.
                    funcDecl.Parent.ReplaceChild(funcDecl, null);

                    // now insert it into the block at the new location, incrementing the location so the next function
                    // will be inserted after it. It is important that they be in the same order as the source, or the semantics
                    // will change when there are functions with the same name.
                    block.Insert(insertAt++, funcDecl);
                }
            }
            else
            {
                // we're already in the right place. Just increment the pointer to move to the next position
                // for next time
                ++insertAt;
            }

            // return the new position
            return insertAt;
        }
        private static int RelocateDirectivePrologue(JsBlock block, int insertAt, JsDirectivePrologue directivePrologue)
        {
            // skip over any important comments
            while (insertAt < block.Count && (block[insertAt] is JsImportantComment))
            {
                ++insertAt;
            }

            // if the one we want to insert is already at this spot, then we're good to go
            if (block[insertAt] != directivePrologue)
            {
                // remove it from where it is right now and insert it into the proper location
                directivePrologue.Parent.ReplaceChild(directivePrologue, null);
                block.Insert(insertAt, directivePrologue);
            }

            // and move up to the next slot
            return ++insertAt;
        }
        private void PossiblyBreakExpressionList(JsBinaryOperator node, JsBlock parentBlock, JsAstNodeList nodeList)
        {
            // if the first item can be broken, then we an break it and be done.
            // otherwise we're going to have to walk until we find a breaking place
            if (CanBeBroken(nodeList[0]))
            {
                // break the first item. insert the left-hand side at our position and
                // recurse it. Then rotate the node.
                var index = parentBlock.IndexOf(node);
                var temp = node.Operand1;
                RotateOpeator(node, nodeList);
                parentBlock.Insert(index, temp);

                // assumes nothing will cause the node to be deleted, because then it
                // would cause us to miss the following item
                temp.Accept(this);
            }
            else
            {
                // the first one can't be broken, so find the first one that can (if any)
                for (var ndx = 1; ndx < nodeList.Count; ++ndx)
                {
                    if (CanBeBroken(nodeList[ndx]))
                    {
                        if (ndx == 1)
                        {
                            // the second item is where we are breaking it, so we're going to pull
                            // the first item, replace the list with that first item, then insert
                            // a new comma operator after the current node
                            var temp = nodeList[0];
                            nodeList.RemoveAt(0);
                            node.Operand2 = temp;

                            // if there's nothing left, then let it die. Otherwise split off
                            // the remainder and insert after the current item.
                            if (nodeList.Count > 0)
                            {
                                parentBlock.InsertAfter(node, CreateSplitNodeFromEnd(nodeList, 0));
                            }
                        }
                        else
                        {
                            // split off items from the index where we want to split, and insert
                            // it after the current node and leave the node list where it is.
                            parentBlock.InsertAfter(node, CreateSplitNodeFromEnd(nodeList, ndx));
                        }

                        // and now that we've broken it, bail.
                        break;
                    }
                }

                // regardless if anything changed, recurse this node now
                base.Visit(node);
            }
        }