private static int RelocateFunction(Block block, int insertAt, FunctionObject 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(Block block, int insertAt, DirectivePrologue directivePrologue) { // skip over any important comments while (insertAt < block.Count && (block[insertAt] is ImportantComment)) { ++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 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) { // 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) { 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 Lookup(varDecl.VariableField.OriginalContext, varDecl.Parser) { Name = varDecl.Identifier, VariableField = varDecl.VariableField, }; assignments.Add(new BinaryOperator(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 = CommaOperator.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 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]; var lookup = new Lookup(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(Block block, int insertAt, FunctionObject 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(Block block, int insertAt, DirectivePrologue directivePrologue) { // skip over any important comments while (insertAt < block.Count && (block[insertAt] is ImportantComment)) { ++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 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) { // 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) { 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 Lookup(varDecl.VariableField.OriginalContext, varDecl.Parser) { Name = varDecl.Identifier, VariableField = varDecl.VariableField, }; assignments.Add(new BinaryOperator(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 = CommaOperator.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 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]; var lookup = new Lookup(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); }