public static AstNode CombineWithComma(Context context, JSParser parser, AstNode operand1, AstNode operand2) { var comma = new CommaOperator(context, parser) { OperatorToken = JSToken.Comma }; // if the left is a comma-operator already.... var leftBinary = operand1 as BinaryOperator; var rightBinary = operand2 as BinaryOperator; if (leftBinary != null && leftBinary.OperatorToken == JSToken.Comma) { // the left-hand side is already a comma operator. Instead of nesting these, we're // going to combine them // move the old list's left-hand side to our left-hand side comma.Operand1 = leftBinary.Operand1; AstNodeList list; if (rightBinary != null && rightBinary.OperatorToken == JSToken.Comma) { // the right is ALSO a comma operator. Create a new list, append all the rest of the operands // and set our right-hand side to be the list list = new AstNodeList(null, parser); list.Append(leftBinary.Operand2).Append(rightBinary.Operand1).Append(rightBinary.Operand2); } else { // the right is not a comma operator. // see if the left-hand side already has a list we can use list = leftBinary.Operand2 as AstNodeList; if (list == null) { // it's not a list already // create a new list with the left's right and our right and set it to our right list = new AstNodeList(null, parser); list.Append(leftBinary.Operand2); } // and add our right-hand operand to the end of the list list.Append(operand2); } // set the list on the right comma.Operand2 = list; } else if (rightBinary != null && rightBinary.OperatorToken == JSToken.Comma) { // the left hand side is NOT a comma operator. comma.Operand1 = operand1; // the right-hand side is already a comma-operator, but the left is not. // see if it already has a list we can reuse var rightList = rightBinary.Operand2 as AstNodeList; if (rightList != null) { // it does. Prepend its right-hand operand and use the list rightList.Insert(0, rightBinary.Operand1); } else { // it's not -- create a new list containing the operands rightList = new AstNodeList(rightBinary.Context, parser); rightList.Append(rightBinary.Operand1); rightList.Append(rightBinary.Operand2); } comma.Operand2 = rightList; } else { comma.Operand1 = operand1; comma.Operand2 = operand2; } return(comma); }
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); }