Esempio n. 1
0
        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);
                    }
                }
            }
        }
Esempio n. 3
0
        /// <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 <Lookup> References(AstNode node)
        {
            var visitor = new BindingsVisitor();

            if (node != null)
            {
                node.Accept(visitor);
            }

            return(visitor.m_lookups);
        }
Esempio n. 4
0
        /// <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);
        }
Esempio n. 5
0
        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);
        }
Esempio n. 8
0
        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();
        }