/// <summary> /// For the given binding node, return a collection of individual lookup /// nodes that represent the names being referenced. /// </summary> /// <param name="node">binding node</param> /// <returns>collection of Lookup nodes</returns> public static IList<LookupExpression> References(AstNode node) { var visitor = new BindingsVisitor(); if (node != null) { node.Accept(visitor); } return visitor.m_lookups; }
/// <summary> /// For the given binding node, return a collection of individual INameDeclaration /// nodes that represent the names being declared for this binding element. /// </summary> /// <param name="node">binding node</param> /// <returns>collection of INameDeclaration nodes</returns> public static IList<BindingIdentifier> Bindings(AstNode node) { var visitor = new BindingsVisitor(); if (node != null) { node.Accept(visitor); } return visitor.m_bindings; }
private static int RelocateForInVar(BlockStatement block, int insertAt, VarDeclaration varStatement, ForInStatement forIn) { // there should only be one decl in the for-in var statement. There should not be any initializer. // If not, then ignore it VariableDeclaration varDecl; if (varStatement.Count == 1 && (varDecl = varStatement[0]).Initializer == null) { // if there are more than three names, then we don't want to move them var bindingNames = BindingsVisitor.Bindings(varDecl.Binding); //if (bindingNames.Count < 3) { // replace the varStatement in the for-in with a reference version of the binding forIn.Variable = BindingTransform.FromBinding(varDecl.Binding); // if this is a simple binding identifier, then leave it as-is. Otherwise we // need to flatten it for the move to the front of the scope. if (!(varDecl.Binding is BindingIdentifier)) { // then flatten all the name in the binding and add them to the var first = true; foreach (var declName in bindingNames) { if (first) { varStatement[0] = new VariableDeclaration(declName.Context) { Binding = new BindingIdentifier(declName.Context) { Name = declName.Name, VariableField = declName.VariableField } }; first = false; } else { // otherwise we want to insert a new one at the current position + 1 varStatement.Append(new VariableDeclaration(declName.Context) { Binding = new BindingIdentifier(declName.Context) { Name = declName.Name, VariableField = declName.VariableField } }); } } } // then move the var statement to the front of the scope // 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 var existingVar = block[insertAt] as VarDeclaration; 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 { // insert it at the insert point block.Insert(insertAt, varStatement); } } } return(insertAt); }
private static int RelocateVar(BlockStatement block, int insertAt, VarDeclaration varStatement) { var forInParent = varStatement.Parent as ForInStatement; if (forInParent != null) { insertAt = ReorderScopeVisitor.RelocateForInVar(block, insertAt, varStatement, forInParent); } else { // 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. ForStatement forStatement; var existingVar = block[insertAt] as VarDeclaration; if (existingVar != null && block[insertAt + 1] == varStatement) { // two var-s one right after the other. // just append our vardecls to the insertion point, then delete our statement existingVar.Append(varStatement); block.RemoveAt(insertAt + 1); } else if (existingVar != null && (forStatement = varStatement.Parent as ForStatement) != null && forStatement.Initializer == varStatement && forStatement == block[insertAt + 1]) { // this var statement is the initializer of a for-statement, which is // immediately after the var we would insert our vardecls into. // rather than moving our vardecls into the outside var-statement, let's // move the outside var-statement into our for-statement. varStatement.InsertAt(0, existingVar); block.RemoveAt(insertAt); } else { // iterate through the decls and count how many have initializers var initializerCount = 0; for (var ndx = 0; ndx < varStatement.Count; ++ndx) { // count the number of vardecls with initializers 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) { // 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; var reference = BindingTransform.FromBinding(varDecl.Binding); if (varDecl.IsCCSpecialCase) { // we don't want to add the special-case to the binary operator class, // so just create a copy of the vardecl for this location, using a reference // for the "binding" assignments.Add(new VariableDeclaration(varDecl.Context) { Binding = reference, AssignContext = varDecl.AssignContext, Initializer = initializer, IsCCSpecialCase = true, UseCCOn = varDecl.UseCCOn, TerminatingContext = varDecl.TerminatingContext }); } else { assignments.Add(new BinaryExpression(varDecl.Context) { Operand1 = reference, Operand2 = initializer, OperatorToken = JSToken.Assign, OperatorContext = varDecl.AssignContext }); } } // if the vardecl we are moving isn't a binding pattern, we need to // break it down into a simple list of names. if (!(varDecl.Binding is BindingIdentifier)) { // place the original vardecl with the first one var first = true; foreach (var declName in BindingsVisitor.Bindings(varDecl.Binding)) { if (first) { varStatement[ndx] = new VariableDeclaration(declName.Context) { Binding = new BindingIdentifier(declName.Context) { Name = declName.Name, VariableField = declName.VariableField } }; first = false; } else { // otherwise we want to insert a new one at the current position + 1 varStatement.InsertAt(++ndx, new VariableDeclaration(declName.Context) { Binding = new BindingIdentifier(declName.Context) { Name = declName.Name, VariableField = declName.VariableField } }); } } } } // 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 = CommaExpression.CombineWithComma(expression.Context.FlattenToStart(), 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. // 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); }