Example #1
0
        public void Visit(JsVariableDeclaration node)
        {
            if (node != null)
            {
                if (node.Parent is JsLexicalDeclaration)
                {
                    // ES6 let or const declaration. Only add to the current lexical scope.
                    CurrentLexicalScope.LexicallyDeclaredNames.Add(node);
                }
                else
                {
                    // must be var or const (mozilla-style). Add to both the lexical scope
                    // and the variable scope. The variable scope will actually use this node
                    // to create a field; the lexical stack will just use it to detect conflicts
                    // with lex-decls
                    CurrentLexicalScope.VarDeclaredNames.Add(node);
                    CurrentVariableScope.VarDeclaredNames.Add(node);
                }

                if (node.Initializer != null)
                {
                    // recurse the initializer
                    node.Initializer.Accept(this);
                    node.Index = NextOrderIndex;
                }
                else
                {
                    // no initializer; give it an index of -1 because it doesn't actually
                    // do anything at execution time.
                    node.Index = -1;
                }
            }
        }
 public void Visit(JsVariableDeclaration node)
 {
     // shoudn't get here
     Debug.Fail("shouldn't get here");
 }
 public void Visit(JsVariableDeclaration node)
 {
     // shoudn't get here
     Debug.Fail("shouldn't get here");
 }
 public void Visit(JsVariableDeclaration node)
 {
     // invalid! ignore
     IsValid = false;
 }
 public void Visit(JsVariableDeclaration node)
 {
     // invalid! ignore
     IsValid = false;
 }
Example #6
0
 public void Visit(JsVariableDeclaration node)
 {
     // not applicable; terminate
 }
 public void Visit(JsVariableDeclaration node)
 {
     // not applicable; terminate
 }
Example #8
0
        //---------------------------------------------------------------------------------------
        // ParseIdentifierInitializer
        //
        //  Does the real work of parsing a single variable declaration.
        //  inToken is JSToken.In whenever the potential expression that initialize a variable
        //  cannot contain an 'in', as in the for statement. inToken is JSToken.None otherwise
        //---------------------------------------------------------------------------------------
        private JsAstNode ParseIdentifierInitializer(JsToken inToken)
        {
            string variableName = null;
            JsAstNode assignmentExpr = null;
            RecoveryTokenException except = null;

            GetNextToken();
            if (JsToken.Identifier != m_currentToken.Token)
            {
                String identifier = JsKeyword.CanBeIdentifier(m_currentToken.Token);
                if (null != identifier)
                {
                    variableName = identifier;
                }
                else
                {
                    // make up an identifier assume we're done with the var statement
                    if (JsScanner.IsValidIdentifier(m_currentToken.Code))
                    {
                        // it's probably just a keyword
                        ReportError(JsError.NoIdentifier, m_currentToken.Clone(), true);
                        variableName = m_currentToken.Code;
                    }
                    else
                    {
                        ReportError(JsError.NoIdentifier);
                        return null;
                    }
                }
            }
            else
            {
                variableName = m_scanner.Identifier;
            }
            JsContext idContext = m_currentToken.Clone();
            JsContext context = m_currentToken.Clone();
            JsContext assignContext = null;

            bool ccSpecialCase = false;
            bool ccOn = false;
            GetNextToken();

            m_noSkipTokenSet.Add(NoSkipTokenSet.s_VariableDeclNoSkipTokenSet);
            try
            {
                if (m_currentToken.Token == JsToken.ConditionalCommentStart)
                {
                    ccSpecialCase = true;

                    GetNextToken();
                    if (m_currentToken.Token == JsToken.ConditionalCompilationOn)
                    {
                        GetNextToken();
                        if (m_currentToken.Token == JsToken.ConditionalCommentEnd)
                        {
                            // forget about it; just ignore the whole thing because it's empty
                            ccSpecialCase = false;
                        }
                        else
                        {
                            ccOn = true;
                        }
                    }
                }

                if (JsToken.Assign == m_currentToken.Token || JsToken.Equal == m_currentToken.Token)
                {
                    assignContext = m_currentToken.Clone();
                    if (JsToken.Equal == m_currentToken.Token)
                    {
                        ReportError(JsError.NoEqual, true);
                    }

                    // move past the equals sign
                    GetNextToken();
                    if (m_currentToken.Token == JsToken.ConditionalCommentEnd)
                    {
                        // so we have var id/*@ =@*/ or var id//@=<EOL>
                        // we only support the equal sign inside conditional comments IF
                        // the initializer value is there as well.
                        ccSpecialCase = false;
                        m_currentToken.HandleError(JsError.ConditionalCompilationTooComplex);
                        GetNextToken();
                    }

                    try
                    {
                        assignmentExpr = ParseExpression(true, inToken);
                    }
                    catch (RecoveryTokenException exc)
                    {
                        assignmentExpr = exc._partiallyComputedNode;
                        throw;
                    }
                    finally
                    {
                        if (null != assignmentExpr)
                        {
                            context.UpdateWith(assignmentExpr.Context);
                        }
                    }
                }
                else if (ccSpecialCase)
                {
                    // so we have "var id /*@" or "var id //@", but the next character is NOT an equal sign.
                    // we don't support this structure, either.
                    ccSpecialCase = false;
                    m_currentToken.HandleError(JsError.ConditionalCompilationTooComplex);

                    // skip to end of conditional comment
                    while (m_currentToken.Token != JsToken.EndOfFile && m_currentToken.Token != JsToken.ConditionalCommentEnd)
                    {
                        GetNextToken();
                    }
                    GetNextToken();
                }

                // if the current token is not an end-of-conditional-comment token now,
                // then we're not in our special case scenario
                if (m_currentToken.Token == JsToken.ConditionalCommentEnd)
                {
                    GetNextToken();
                }
                else if (ccSpecialCase)
                {
                    // we have "var id/*@=expr" but the next token is not the closing comment.
                    // we don't support this structure, either.
                    ccSpecialCase = false;
                    m_currentToken.HandleError(JsError.ConditionalCompilationTooComplex);

                    // the assignment expression was apparently wiothin the conditional compilation
                    // comment, but we're going to ignore it. So clear it out.
                    assignmentExpr = null;

                    // skip to end of conditional comment
                    while (m_currentToken.Token != JsToken.EndOfFile && m_currentToken.Token != JsToken.ConditionalCommentEnd)
                    {
                        GetNextToken();
                    }
                    GetNextToken();
                }
            }
            catch (RecoveryTokenException exc)
            {
                // If the exception is in the vardecl no-skip set then we successfully
                // recovered to the end of the declaration and can just return
                // normally.  Otherwise we re-throw after constructing the partial result.
                if (IndexOfToken(NoSkipTokenSet.s_VariableDeclNoSkipTokenSet, exc) == -1)
                    except = exc;
            }
            finally
            {
                m_noSkipTokenSet.Remove(NoSkipTokenSet.s_VariableDeclNoSkipTokenSet);
            }

            JsVariableDeclaration result = new JsVariableDeclaration(context, this)
                {
                    Identifier = variableName,
                    NameContext = idContext,
                    AssignContext = assignContext,
                    Initializer = assignmentExpr
                };

            result.IsCCSpecialCase = ccSpecialCase;
            if (ccSpecialCase)
            {
                // by default, set the flag depending on whether we encountered a @cc_on statement.
                // might be overridden by the node in analyze phase
                result.UseCCOn = ccOn;
            }

            if (null != except)
            {
                except._partiallyComputedNode = result;
                throw except;
            }

            return result;
        }
        public void Visit(JsVariableDeclaration node)
        {
            if (node != null)
            {
                if (node.Parent is JsLexicalDeclaration)
                {
                    // ES6 let or const declaration. Only add to the current lexical scope.
                    CurrentLexicalScope.LexicallyDeclaredNames.Add(node);
                }
                else
                {
                    // must be var or const (mozilla-style). Add to both the lexical scope
                    // and the variable scope. The variable scope will actually use this node
                    // to create a field; the lexical stack will just use it to detect conflicts
                    // with lex-decls
                    CurrentLexicalScope.VarDeclaredNames.Add(node);
                    CurrentVariableScope.VarDeclaredNames.Add(node);
                }

                if (node.Initializer != null)
                {
                    // recurse the initializer
                    node.Initializer.Accept(this);
                    node.Index = NextOrderIndex;
                }
                else
                {
                    // no initializer; give it an index of -1 because it doesn't actually
                    // do anything at execution time.
                    node.Index = -1;
                }
            }
        }
        private static int RelocateVar(JsBlock block, int insertAt, JsVar 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 JsVar;
                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 <JsAstNode>();
                        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 JsVariableDeclaration(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 JsLookup(varDecl.VariableField.OriginalContext, varDecl.Parser)
                                    {
                                        Name          = varDecl.Identifier,
                                        VariableField = varDecl.VariableField,
                                    };
                                    assignments.Add(new JsBinaryOperator(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 = JsCommaOperator.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 JsForIn;
                            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 JsLookup(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);
        }
        public void Visit(JsVariableDeclaration node)
        {
            if (node != null)
            {
                var symbol = StartSymbol(node);

                // output the name (use the field is possible)
                Output(node.VariableField != null ? node.VariableField.ToString() : node.Identifier);
                MarkSegment(node, node.Name, node.Context);
                SetContextOutputPosition(node.Context);
                node.VariableField.IfNotNull(f => SetContextOutputPosition(f.OriginalContext));

                m_startOfStatement = false;
                if (node.Initializer != null)
                {
                    if (node.IsCCSpecialCase)
                    {
                        // we haven't output a cc_on yet -- output it now.
                        // if we have, we really only need to output one if we had one to begin with AND
                        // we are NOT removing unnecessary ones
                        if (!m_outputCCOn
                            || (node.UseCCOn && !m_settings.IsModificationAllowed(JsTreeModifications.RemoveUnnecessaryCCOnStatements)))
                        {
                            Output("/*@cc_on=");
                            m_outputCCOn = true;
                        }
                        else
                        {
                            Output("/*@=");
                        }
                    }
                    else
                    {

                        if (m_settings.OutputMode == MinifierOutputMode.MultipleLines && m_settings.IndentSize > 0)
                        {
                            OutputPossibleLineBreak(' ');
                            OutputPossibleLineBreak('=');
                            BreakLine(false);
                            if (!m_onNewLine)
                            {
                                OutputPossibleLineBreak(' ');
                            }
                        }
                        else
                        {
                            OutputPossibleLineBreak('=');
                        }
                    }

                    AcceptNodeWithParens(node.Initializer, node.Initializer.Precedence == JsOperatorPrecedence.Comma);

                    if (node.IsCCSpecialCase)
                    {
                        Output("@*/");
                    }
                }

                EndSymbol(symbol);
            }
        }
        private static int RelocateVar(JsBlock block, int insertAt, JsVar 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 JsVar;
                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<JsAstNode>();
                        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 JsVariableDeclaration(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 JsLookup(varDecl.VariableField.OriginalContext, varDecl.Parser)
                                        {
                                            Name = varDecl.Identifier,
                                            VariableField = varDecl.VariableField,
                                        };
                                    assignments.Add(new JsBinaryOperator(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 = JsCommaOperator.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 JsForIn;
                            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 JsLookup(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;
        }
 private static void ConvertAssignmentsToVarDecls(JsBinaryOperator binaryOp, List<JsVariableDeclaration> varDecls, JsParser parser)
 {
     // we've already checked that the tree only contains simple assignments separate by commas,
     // but just in case we'll check for null anyway
     if (binaryOp != null)
     {
         if (binaryOp.OperatorToken == JsToken.Assign)
         {
             // we've already cleared this as a simple lookup, but run the check just to be sure
             JsLookup lookup = binaryOp.Operand1 as JsLookup;
             if (lookup != null)
             {
                 var varDecl = new JsVariableDeclaration(binaryOp.Context.Clone(), parser)
                     {
                         Identifier = lookup.Name,
                         NameContext = lookup.Context.Clone(),
                         AssignContext = binaryOp.OperatorContext,
                         Initializer = binaryOp.Operand2,
                         VariableField = lookup.VariableField
                     };
                 varDecl.VariableField.Declarations.Add(varDecl);
                 varDecls.Add(varDecl);
             }
         }
         else if (binaryOp.OperatorToken == JsToken.Comma)
         {
             // recurse both operands
             ConvertAssignmentsToVarDecls(binaryOp.Operand1 as JsBinaryOperator, varDecls, parser);
             ConvertAssignmentsToVarDecls(binaryOp.Operand2 as JsBinaryOperator, varDecls, parser);
         }
         // shouldn't ever be anything but these two operators
     }
 }
        public override void Visit(JsVariableDeclaration node)
        {
            if (node != null)
            {
                base.Visit(node);

                // check the name of the variable for reserved words that aren't allowed
                if (JsScanner.IsKeyword(node.Identifier, m_scopeStack.Peek().UseStrict))
                {
                    node.Context.HandleError(JsError.KeywordUsedAsIdentifier, true);
                }
                else if (m_scopeStack.Peek().UseStrict
                    && (string.CompareOrdinal(node.Identifier, "eval") == 0
                    || string.CompareOrdinal(node.Identifier, "arguments") == 0))
                {
                    // strict mode cannot declare variables named "eval" or "arguments"
                    node.NameContext.HandleError(JsError.StrictModeVariableName, true);
                }

                // if this is a special-case vardecl (var foo/*@cc_on=EXPR@*/), set the flag indicating
                // we encountered a @cc_on statement if we found one
                if (node.IsCCSpecialCase && m_parser.Settings.IsModificationAllowed(JsTreeModifications.RemoveUnnecessaryCCOnStatements))
                {
                    node.UseCCOn = !m_encounteredCCOn;
                    m_encounteredCCOn = true;
                }
            }
        }