public override bool IsEquivalentTo(AstNode otherNode) { // EVERYTHING referenced in the other node needs to be represented // in the bindings of this node. This node can have MORE, though; that's okay. var everythingRepresented = true; var theseBindings = BindingsVisitor.Bindings(this.Binding); foreach (var reference in BindingsVisitor.References(otherNode)) { var foundOne = false; foreach (var bindingIdentifier in theseBindings) { if (bindingIdentifier.IsEquivalentTo(reference)) { foundOne = true; break; } } if (!foundOne) { everythingRepresented = false; break; } } return(everythingRepresented); }
private void DefineParameters() { var functionObject = (FunctionObject)Owner; if (functionObject.ParameterDeclarations != null) { // for each parameter... foreach (ParameterDeclaration parameter in functionObject.ParameterDeclarations) { foreach (var nameDeclaration in BindingsVisitor.Bindings(parameter.Binding)) { // see if it's already defined var argumentField = this[nameDeclaration.Name]; if (argumentField == null) { // not already defined -- create a field now argumentField = new JSVariableField(FieldType.Argument, nameDeclaration.Name, 0, null) { Position = parameter.Position, OriginalContext = parameter.Context, CanCrunch = !nameDeclaration.RenameNotAllowed }; this.AddField(argumentField); } // make the parameter reference the field and the field reference // the parameter as its declaration nameDeclaration.VariableField = argumentField; argumentField.Declarations.Add(nameDeclaration); } } } }
public bool Contains(string name) { if (!name.IsNullOrWhiteSpace()) { // look at each vardecl in our list foreach (var varDecl in m_list) { foreach (var nameDeclaration in BindingsVisitor.Bindings(varDecl)) { // if it matches the target name exactly... if (string.CompareOrdinal(name, nameDeclaration.Name) == 0) { // ...we found a match return(true); } } } } // if we get here, we didn't find any matches return(false); }
private static int RelocateForInVar(Block block, int insertAt, Var varStatement, ForIn 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 Var; 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(Block block, int insertAt, Var varStatement) { var forInParent = varStatement.Parent as ForIn; 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. ForNode forNode; var existingVar = block[insertAt] as Var; 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 && (forNode = varStatement.Parent as ForNode) != null && forNode.Initializer == varStatement && forNode == 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 BinaryOperator(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 = CommaOperator.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); }
private void ProcessScope(ActivationObject scope) { switch (scope.ScopeType) { case ScopeType.Block: case ScopeType.Lexical: case ScopeType.None: // must be generic block scope m_writer.WriteStartElement("block"); if (scope.UseStrict) { m_writer.WriteAttributeString("strict", "true"); } break; case ScopeType.Class: m_writer.WriteStartElement("class"); if (!scope.ScopeName.IsNullOrWhiteSpace()) { m_writer.WriteAttributeString("src", scope.ScopeName); } if (scope.UseStrict) { m_writer.WriteAttributeString("strict", "true"); } break; case ScopeType.Catch: var catchScope = (CatchScope)scope; m_writer.WriteStartElement("catch"); if (scope.UseStrict) { m_writer.WriteAttributeString("strict", "true"); } foreach (var bindingIdentifier in BindingsVisitor.Bindings(catchScope.CatchParameter)) { m_writer.WriteStartElement("catchvar"); m_writer.WriteAttributeString("src", bindingIdentifier.Name); OutputContextPosition(bindingIdentifier.Context); var catchVariable = bindingIdentifier.VariableField; if (catchVariable != null) { if (catchVariable.CrunchedName != null) { m_writer.WriteAttributeString("min", catchVariable.CrunchedName); } if (m_useReferenceCounts) { m_writer.WriteAttributeString("refcount", catchVariable.RefCount.ToStringInvariant()); } } m_writer.WriteEndElement(); } break; case ScopeType.Module: m_writer.WriteStartElement("module"); if (!scope.ScopeName.IsNullOrWhiteSpace()) { m_writer.WriteAttributeString("name", scope.ScopeName); } if (scope.UseStrict) { m_writer.WriteAttributeString("strict", "true"); } (scope as ModuleScope).IfNotNull(m => { m_writer.WriteAttributeString("default", m.HasDefaultExport ? "true" : "false"); if (m.IsNotComplete) { m_writer.WriteAttributeString("incomplete", "true"); } }); break; case ScopeType.Function: var functionScope = (FunctionScope)scope; m_writer.WriteStartElement("function"); // for source name, use the scope name if (!scope.ScopeName.IsNullOrWhiteSpace()) { m_writer.WriteAttributeString("src", scope.ScopeName); } var functionObject = functionScope.Owner as FunctionObject; if (functionObject != null) { if (functionObject.Binding == null || functionObject.Binding.Name.IsNullOrWhiteSpace()) { if (!functionObject.NameGuess.IsNullOrWhiteSpace()) { // strip enclosing quotes m_writer.WriteAttributeString("guess", functionObject.NameGuess.Trim('\"')); } } else { if (functionObject.Binding.VariableField != null && functionObject.Binding.VariableField.CrunchedName != null) { m_writer.WriteAttributeString("min", functionObject.Binding.VariableField.CrunchedName); } } m_writer.WriteAttributeString("type", functionObject.FunctionType.ToString().ToLowerInvariant()); OutputContextPosition(functionObject.Context); if (m_useReferenceCounts && functionObject.Binding != null && functionObject.Binding.VariableField != null) { var refCount = functionObject.Binding.VariableField.RefCount; m_writer.WriteAttributeString("refcount", refCount.ToStringInvariant()); if (refCount == 0 && functionObject.FunctionType == FunctionType.Declaration && functionObject.Binding.VariableField.FieldType == FieldType.Local) { // local function declaration with zero references? unreachable code! m_writer.WriteAttributeString("unreachable", "true"); } } if (scope.UseStrict) { m_writer.WriteAttributeString("strict", "true"); } // add the arguments m_writer.WriteStartElement("arguments"); if (functionObject.ParameterDeclarations != null) { foreach (var bindingIdentifier in BindingsVisitor.Bindings(functionObject.ParameterDeclarations)) { m_writer.WriteStartElement("argument"); m_writer.WriteAttributeString("src", bindingIdentifier.Name); if (bindingIdentifier.VariableField.IfNotNull(v => v.CrunchedName != null)) { m_writer.WriteAttributeString("min", bindingIdentifier.VariableField.CrunchedName); } OutputContextPosition(bindingIdentifier.Context); if (m_useReferenceCounts) { bindingIdentifier.VariableField.IfNotNull(v => m_writer.WriteAttributeString("refcount", v.RefCount.ToStringInvariant())); } m_writer.WriteEndElement(); } } m_writer.WriteEndElement(); } break; case ScopeType.Global: Debug.Assert(scope is GlobalScope); Debug.Fail("shouldn't get here!"); m_writer.WriteStartElement("global"); break; case ScopeType.With: Debug.Assert(scope is WithScope); m_writer.WriteStartElement("with"); // with-scopes should never be strict because the with-statement is not allowed in strict code if (scope.UseStrict) { m_writer.WriteAttributeString("strict", "true"); } break; } // process the defined and referenced fields ProcessFields(scope); // recursively process each child scope foreach (var childScope in scope.ChildScopes) { ProcessScope(childScope); } // close the element m_writer.WriteEndElement(); }