示例#1
0
        public override bool IsEquivalentTo(JsAstNode otherNode)
        {
            // a binary operator is equivalent to another binary operator if the operator is the same and
            // both operands are also equivalent
            var otherBinary = otherNode as JsBinaryOperator;

            return(otherBinary != null &&
                   OperatorToken == otherBinary.OperatorToken &&
                   Operand1.IsEquivalentTo(otherBinary.Operand1) &&
                   Operand2.IsEquivalentTo(otherBinary.Operand2));
        }
        public static bool Apply(TextWriter writer, JsAstNode node)
        {
            if (node != null)
            {
                var visitor = new JsonOutputVisitor(writer);
                node.Accept(visitor);
                return(visitor.IsValid);
            }

            return(false);
        }
示例#3
0
        public override bool IsEquivalentTo(JsAstNode otherNode)
        {
            // a call node is equivalent to another call node if the function and the arguments
            // are all equivalent (and be sure to check for brackets and constructor)
            var otherCall = otherNode as JsCallNode;

            return(otherCall != null &&
                   this.InBrackets == otherCall.InBrackets &&
                   this.IsConstructor == otherCall.IsConstructor &&
                   this.Function.IsEquivalentTo(otherCall.Function) &&
                   this.Arguments.IsEquivalentTo(otherCall.Arguments));
        }
 public override bool ReplaceChild(JsAstNode oldNode, JsAstNode newNode)
 {
     if (oldNode == m_properties)
     {
         var properties = newNode as JsAstNodeList;
         if (newNode == null || properties != null)
         {
             Properties = properties;
         }
     }
     return(false);
 }
        private static bool IsIterativeReference(JsAstNode initializer, IJsNameReference reference)
        {
            // we only care about array and regular expressions with the global switch at this point.
            // if it's not one of those types, then go ahead and assume iterative reference doesn't matter.
            var regExp = initializer as JsRegExpLiteral;

            if (initializer is JsArrayLiteral ||
                initializer is JsObjectLiteral ||
                (regExp != null && regExp.PatternSwitches != null && regExp.PatternSwitches.IndexOf("g", StringComparison.OrdinalIgnoreCase) >= 0))
            {
                // get the parent block for the initializer. We'll use this as a stopping point in our loop.
                var parentBlock = GetParentBlock(initializer);

                // walk up the parent chain from the reference. If we find a while, a for, or a do-while,
                // then we know this reference is iteratively called.
                // stop when the parent is null, the same block containing the initializer, or a function object.
                // (because a function object will step out of scope, and we know we should be in the same scope)
                var child  = reference as JsAstNode;
                var parent = child.Parent;
                while (parent != null && parent != parentBlock && !(parent is JsFunctionObject))
                {
                    // while or do-while is iterative -- the condition and the body are both called repeatedly.
                    if (parent is JsWhileNode || parent is JsDoWhile)
                    {
                        return(true);
                    }

                    // for-statements call the condition, the incrementer, and the body repeatedly, but not the
                    // initializer.
                    var forNode = parent as JsForNode;
                    if (forNode != null && child != forNode.Initializer)
                    {
                        return(true);
                    }

                    // in forin-statements, only the body is repeated, the collection is evaluated only once.
                    var forInStatement = parent as JsForIn;
                    if (forInStatement != null && child == forInStatement.Body)
                    {
                        return(true);
                    }

                    // go up
                    child  = parent;
                    parent = parent.Parent;
                }
            }

            return(false);
        }
示例#6
0
 public override bool ReplaceChild(JsAstNode oldNode, JsAstNode newNode)
 {
     if (WithObject == oldNode)
     {
         WithObject = newNode;
         return(true);
     }
     if (Body == oldNode)
     {
         Body = ForceToBlock(newNode);
         return(true);
     }
     return(false);
 }
示例#7
0
 public override bool ReplaceChild(JsAstNode oldNode, JsAstNode newNode)
 {
     if (Condition == oldNode)
     {
         Condition = newNode;
         return(true);
     }
     if (Body == oldNode)
     {
         Body = ForceToBlock(newNode);
         return(true);
     }
     return(false);
 }
示例#8
0
 public override bool ReplaceChild(JsAstNode oldNode, JsAstNode newNode)
 {
     if (Operand1 == oldNode)
     {
         Operand1 = newNode;
         return(true);
     }
     if (Operand2 == oldNode)
     {
         Operand2 = newNode;
         return(true);
     }
     return(false);
 }
示例#9
0
        public static JsBlock ForceToBlock(JsAstNode node)
        {
            // if the node is null or already a block, then we're
            // good to go -- just return it.
            var block = node as JsBlock;

            if (block == null && node != null)
            {
                // it's not a block, so create a new block, append the astnode
                // and return the block
                block = new JsBlock(node.Context.Clone(), node.Parser);
                block.Append(node);
            }

            return(block);
        }
示例#10
0
 /// <summary>
 /// Insert a new node into the given position index within the block
 /// </summary>
 /// <param name="position">zero-based index into which the new node will be inserted</param>
 /// <param name="item">new node to insert into the block</param>
 public void Insert(int position, JsAstNode item)
 {
     if (item != null)
     {
         var block = item as JsBlock;
         if (block != null)
         {
             InsertRange(position, block.Children);
         }
         else
         {
             item.Parent = this;
             m_list.Insert(position, item);
         }
     }
 }
示例#11
0
        public void MarkSegment(JsAstNode node, int startLine, int startColumn, string name, JsContext context)
        {
            if (startLine == int.MaxValue)
            {
                throw new ArgumentOutOfRangeException("startLine");
            }

            // add the offsets
            startLine   += m_lineOffset;
            startColumn += m_columnOffset;

            // if we have a name, try adding it to the hash set of names. If it already exists, the call to Add
            // will return false. If it doesn't already exist, Add will return true and we'll append it to the list
            // of names. That way we have a nice list of names ordered by their first occurrence in the minified file.
            if (!string.IsNullOrEmpty(name) && m_names.Add(name))
            {
                m_nameList.Add(name);
            }

            // if this is a newline, the startline will be bigger than the largest line we've had so far
            m_maxMinifiedLine = Math.Max(m_maxMinifiedLine, startLine);

            // save the file context in our list of files
            if (context != null && context.Document != null && context.Document.FileContext != null)
            {
                // if this is the first instance of this file...
                if (m_sourceFiles.Add(context.Document.FileContext))
                {
                    // ...add it to the list, so we end up with a list of unique files
                    // sorted by their first occurence in the minified file.
                    m_sourceFileList.Add(MakeRelative(context.Document.FileContext, m_mapPath));
                }
            }

            // create the segment object and add it to the list.
            // the destination line/col numbers are zero-based. The format expects line to be 1-based and col 0-based.
            // the context line is one-based; col is zero-based. The format expects both to be zero-based.
            var segment = CreateSegment(
                startLine + 1,
                startColumn,
                context == null || context.StartLineNumber < 1 ? -1 : context.StartLineNumber - 1,
                context == null || context.StartColumn < 0 ? -1 : context.StartColumn,
                context.IfNotNull(c => MakeRelative(c.Document.FileContext, m_mapPath)),
                name);

            m_segments.Add(segment);
        }
示例#12
0
 public override bool ReplaceChild(JsAstNode oldNode, JsAstNode newNode)
 {
     if (CaseValue == oldNode)
     {
         CaseValue = newNode;
         return(true);
     }
     if (Statements == oldNode)
     {
         var newBlock = newNode as JsBlock;
         if (newNode == null || newBlock != null)
         {
             Statements = newBlock;
             return(true);
         }
     }
     return(false);
 }
示例#13
0
 private void TypicalHandler(JsAstNode node)
 {
     if (node != null)
     {
         // don't need to recurse -- to logical-not this, we just need to apply
         // the logical-not operator to it, which will add a character
         if (m_measure)
         {
             // measure
             ++m_delta;
         }
         else
         {
             // simple convert
             WrapWithLogicalNot(node);
         }
     }
 }
示例#14
0
        public override bool IsEquivalentTo(JsAstNode otherNode)
        {
            JsVariableField otherField = null;
            JsLookup        otherLookup;
            var             otherVarDecl = otherNode as JsVariableDeclaration;

            if (otherVarDecl != null)
            {
                otherField = otherVarDecl.VariableField;
            }
            else if ((otherLookup = otherNode as JsLookup) != null)
            {
                otherField = otherLookup.VariableField;
            }

            // if we get here, we're not equivalent
            return(this.VariableField != null && this.VariableField.IsSameField(otherField));
        }
        /// <summary>
        /// Return the first Block node in the tree starting from the given node and working up through the parent nodes.
        /// </summary>
        /// <param name="node">initial node</param>
        /// <returns>first block node in the node tree</returns>
        private static JsBlock GetParentBlock(JsAstNode node)
        {
            while (node != null)
            {
                // see if the current node is a block, and if so, return it.
                var block = node as JsBlock;
                if (block != null)
                {
                    return(block);
                }

                // try the parent
                node = node.Parent;
            }

            // if we get here, we never found a parent block.
            return(null);
        }
        public override bool ReplaceChild(JsAstNode oldNode, JsAstNode newNode)
        {
            if (Body == oldNode)
            {
                Body = ForceToBlock(newNode);
                return(true);
            }
            else if (ParameterDeclarations == oldNode)
            {
                var newList = newNode as JsAstNodeList;
                if (newNode == null || newList != null)
                {
                    ParameterDeclarations = newList;
                    return(true);
                }
            }

            return(false);
        }
示例#17
0
        private bool CanBeBroken(JsAstNode node)
        {
            JsAstNodeList nodeList;

            if (!m_statementStart.IsSafe(node))
            {
                // don't break if the next statement is a function or an object literal
                return(false);
            }
            else if ((nodeList = node as JsAstNodeList) != null)
            {
                // if there aren't any operands in the list, we can break this,
                // otherwise check to see if the first item can be broken.
                return(nodeList.Count == 0 || CanBeBroken(nodeList[0]));
            }

            // if we get here, it's okay to break this operation into separate statements
            return(true);
        }
示例#18
0
 public override bool ReplaceChild(JsAstNode oldNode, JsAstNode newNode)
 {
     if (Condition == oldNode)
     {
         Condition = newNode;
         return(true);
     }
     if (TrueExpression == oldNode)
     {
         TrueExpression = newNode;
         return(true);
     }
     if (FalseExpression == oldNode)
     {
         FalseExpression = newNode;
         return(true);
     }
     return(false);
 }
示例#19
0
        public override bool ReplaceChild(JsAstNode oldNode, JsAstNode newNode)
        {
            if (Name == oldNode)
            {
                var objectField = newNode as JsObjectLiteralField;
                if (newNode == null || objectField != null)
                {
                    Name = objectField;
                }
                return(true);
            }

            if (Value == oldNode)
            {
                Value = newNode;
                return(true);
            }

            return(false);
        }
示例#20
0
        public override bool ReplaceChild(JsAstNode oldNode, JsAstNode newNode)
        {
            if (Expression == oldNode)
            {
                Expression = newNode;
                return(true);
            }
            if (Cases == oldNode)
            {
                JsAstNodeList newList = newNode as JsAstNodeList;
                if (newNode == null || newList != null)
                {
                    // remove it
                    Cases = newList;
                    return(true);
                }
            }

            return(false);
        }
示例#21
0
        public override bool ReplaceChild(JsAstNode oldNode, JsAstNode newNode)
        {
            for (int ndx = 0; ndx < m_list.Count; ++ndx)
            {
                if (m_list[ndx] == oldNode)
                {
                    // if the new node isn't a variabledeclaration, ignore the call
                    JsVariableDeclaration newDecl = newNode as JsVariableDeclaration;
                    if (newNode == null || newDecl != null)
                    {
                        m_list[ndx].IfNotNull(n => n.Parent = (n.Parent == this) ? null : n.Parent);
                        m_list[ndx] = newDecl;
                        m_list[ndx].IfNotNull(n => n.Parent = this);
                        return(true);
                    }

                    break;
                }
            }
            return(false);
        }
示例#22
0
 /// <summary>
 /// Insert the given statement node after an existing node in the block.
 /// </summary>
 /// <param name="after">exisitng child node of the block</param>
 /// <param name="item">node to insert after the existing node</param>
 public void InsertAfter(JsAstNode after, JsAstNode item)
 {
     if (item != null)
     {
         int index = m_list.IndexOf(after);
         if (index >= 0)
         {
             var block = item as JsBlock;
             if (block != null)
             {
                 // don't insert a block into a block -- insert the new block's
                 // children instead (don't want nested blocks)
                 InsertRange(index + 1, block.Children);
             }
             else
             {
                 item.Parent = this;
                 m_list.Insert(index + 1, item);
             }
         }
     }
 }
        public void MarkSegment(JsAstNode node, int startLine, int startColumn, string name, JsContext context)
        {
            if (node == null || string.IsNullOrEmpty(name))
            {
                return;
            }

            // see if this is within a function object node,
            // AND if this segment has the same name as the function name
            // AND this context isn't the same as the entire function context.
            // this should only be true for the function NAME segment.
            var functionObject = node as JsFunctionObject;

            if (functionObject != null &&
                string.CompareOrdinal(name, functionObject.Name) == 0 &&
                context != functionObject.Context)
            {
                // adjust the offsets
                startLine   += m_lineOffset;
                startColumn += m_columnOffset;

                // it does -- so this is the segment that corresponds to the function object's name, which
                // for this format we want to output a separate segment for. It used to be its own Lookup
                // node child of the function object, so we need to create a fake node here, start a new
                // symbol from it, end the symbol, then write it.
                var fakeLookup = new JsLookup(context, functionObject.Parser)
                {
                    Name = name
                };
                var nameSymbol = JavaScriptSymbol.StartNew(fakeLookup, startLine, startColumn, GetSourceFileIndex(functionObject.Context.Document.FileContext));

                // the name will never end on a different line -- it's a single unbreakable token. The length is just
                // the length of the name, so add that number to the column start. And the parent context is the function
                // name (again)
                nameSymbol.End(startLine, startColumn + name.Length, name);
                nameSymbol.WriteTo(m_writer);
            }
        }
示例#24
0
        public override bool IsEquivalentTo(JsAstNode otherNode)
        {
            // this one is tricky. If we have a field assigned, then we are equivalent if the
            // field is the same as the other one. If there is no field, then just check the name
            var otherLookup = otherNode as JsLookup;

            if (otherLookup != null)
            {
                if (VariableField != null)
                {
                    // the variable fields should be the same
                    return(VariableField.IsSameField(otherLookup.VariableField));
                }
                else
                {
                    // otherwise the names should be identical
                    return(string.CompareOrdinal(Name, otherLookup.Name) == 0);
                }
            }

            // if we get here, we're not equivalent
            return(false);
        }
示例#25
0
        public bool Match(JsAstNode node, string identifiers)
        {
            // set the match to false
            m_isMatch = false;

            // identifiers cannot be null or blank and must match: IDENT(.IDENT)*
            // since for JS there has to be at least a global object, the dot must be AFTER the first character.
            if (node != null && !string.IsNullOrEmpty(identifiers))
            {
                // get all the parts
                var parts = identifiers.Split('.');

                // each part must be a valid JavaScript identifier. Assume everything is valid
                // unless at least one is invalid -- then forget it
                var isValid = true;
                foreach (var part in parts)
                {
                    if (!JsScanner.IsValidIdentifier(part))
                    {
                        isValid = false;
                        break;
                    }
                }

                // must be valid to continue
                if (isValid)
                {
                    // save the parts and start the index on the last one, since we'll be walking backwards
                    m_parts = parts;
                    m_index = parts.Length - 1;

                    node.Accept(this);
                }
            }

            return(m_isMatch);
        }
示例#26
0
        /// <summary>
        /// Replace the existing direct child node of the block with a new node.
        /// </summary>
        /// <param name="oldNode">existing statement node to replace.</param>
        /// <param name="newNode">node with which to replace the existing node.</param>
        /// <returns>true if the replacement was a succeess; false otherwise</returns>
        public override bool ReplaceChild(JsAstNode oldNode, JsAstNode newNode)
        {
            for (int ndx = m_list.Count - 1; ndx >= 0; --ndx)
            {
                if (m_list[ndx] == oldNode)
                {
                    m_list[ndx].IfNotNull(n => n.Parent = (n.Parent == this) ? null : n.Parent);
                    if (newNode == null)
                    {
                        // just remove it
                        m_list.RemoveAt(ndx);
                    }
                    else
                    {
                        JsBlock newBlock = newNode as JsBlock;
                        if (newBlock != null)
                        {
                            // the new "statement" is a block. That means we need to insert all
                            // the statements from the new block at the location of the old item.
                            m_list.RemoveAt(ndx);
                            InsertRange(ndx, newBlock.m_list);
                        }
                        else
                        {
                            // not a block -- slap it in there
                            m_list[ndx]    = newNode;
                            newNode.Parent = this;
                        }
                    }

                    return(true);
                }
            }

            return(false);
        }
示例#27
0
        public static void Apply(JsAstNode node, JsActivationObject scope, JsSettings settings)
        {
            if (node != null && scope != null)
            {
                // create the visitor and run it. This will create all the child
                // scopes and populate all the scopes with the var-decl, lex-decl,
                // and lookup references within them.
                var visitor = new JsResolutionVisitor(scope, settings);
                node.Accept(visitor);

                // now that all the scopes are created and they all know what decls
                // they contains, create all the fields
                CreateFields(scope);

                // now that all the fields have been created in all the scopes,
                // let's go through and resolve all the references
                ResolveLookups(scope, settings);

                // now that everything is declared and resolved as per the language specs,
                // we need to go back and add ghosted fields for older versions of IE that
                // incorrectly implement catch-variables and named function expressions.
                AddGhostedFields(scope);
            }
        }
示例#28
0
        private static bool MatchesMemberChain(JsAstNode parent, string lookup, int startIndex)
        {
            // get the NEXT period
            var period = lookup.IndexOf('.', startIndex);

            // loop until we run out of periods
            while (period > 0)
            {
                // if the parent isn't a member, or if the name of the parent doesn't match
                // the current identifier in the chain, then we're no match and can bail
                if (!MatchMemberName(parent, lookup, startIndex, period))
                {
                    return(false);
                }

                // next parent, next segment, and find the next period
                parent     = parent.Parent;
                startIndex = period + 1;
                period     = lookup.IndexOf('.', startIndex);
            }

            // now check the last segment, from start to the end of the string
            return(MatchMemberName(parent, lookup, startIndex, lookup.Length));
        }
            public static JavaScriptSymbol StartNew(JsAstNode node, int startLine, int startColumn, int sourceFileId)
            {
                if (startLine == int.MaxValue)
                {
                    throw new ArgumentOutOfRangeException("startLine");
                }

                if (startColumn == int.MaxValue)
                {
                    throw new ArgumentOutOfRangeException("startColumn");
                }

                return(new JavaScriptSymbol
                {
                    // destination line/col number are fed to us as zero-based, so add one to get to
                    // the one-based values we desire. Context objects store the source line/col as
                    // one-based already.
                    m_startLine = startLine + 1,
                    m_startColumn = startColumn + 1,
                    m_sourceContext = node != null ? node.Context : null,
                    m_symbolType = node != null?node.GetType().Name : "[UNKNOWN]",
                    m_sourceFileId = sourceFileId,
                });
            }
示例#30
0
 public override bool ReplaceChild(JsAstNode oldNode, JsAstNode newNode)
 {
     if (TryBlock == oldNode)
     {
         TryBlock = ForceToBlock(newNode);
         return(true);
     }
     if (CatchParameter == oldNode)
     {
         CatchParameter = newNode as JsParameterDeclaration;
         return(true);
     }
     if (CatchBlock == oldNode)
     {
         CatchBlock = ForceToBlock(newNode);
         return(true);
     }
     if (FinallyBlock == oldNode)
     {
         FinallyBlock = ForceToBlock(newNode);
         return(true);
     }
     return(false);
 }