Пример #1
0
 public void Visit(JsDirectivePrologue node)
 {
     if (node != null)
     {
         node.Index = NextOrderIndex;
         if (node.UseStrict)
         {
             CurrentVariableScope.UseStrict = true;
         }
     }
 }
        private static int RelocateDirectivePrologue(JsBlock block, int insertAt, JsDirectivePrologue directivePrologue)
        {
            // skip over any important comments
            while (insertAt < block.Count && (block[insertAt] is JsImportantComment))
            {
                ++insertAt;
            }

            // if the one we want to insert is already at this spot, then we're good to go
            if (block[insertAt] != directivePrologue)
            {
                // remove it from where it is right now and insert it into the proper location
                directivePrologue.Parent.ReplaceChild(directivePrologue, null);
                block.Insert(insertAt, directivePrologue);
            }

            // and move up to the next slot
            return(++insertAt);
        }
        public override void Visit(JsDirectivePrologue node)
        {
            if (node != null)
            {
                // if this is a minification hint, then process it now
                // and then remove it. Otherwise treat it as a directive prologue that
                // we need to preserve
                if (IsMinificationHint(node))
                {
                    node.Parent.ReplaceChild(node, null);
                }
                else
                {
                    // no need to call the base, just add it to the list
                    if (m_moduleDirectives == null)
                    {
                        m_moduleDirectives = new List <JsDirectivePrologue>();
                    }

                    m_moduleDirectives.Add(node);
                }
            }
        }
 public void Visit(JsDirectivePrologue node)
 {
     // invalid! ignore
     IsValid = false;
 }
 public void Visit(JsDirectivePrologue node)
 {
     // invalid! ignore
     IsValid = false;
 }
Пример #6
0
 public void Visit(JsDirectivePrologue node)
 {
     // not applicable; terminate
 }
 public void Visit(JsDirectivePrologue node)
 {
     // not applicable; terminate
 }
 public void Visit(JsDirectivePrologue node)
 {
     Debug.Fail("shouldn't get here");
 }
Пример #9
0
        //---------------------------------------------------------------------------------------
        // ParseStatements
        //
        // statements :
        //   <empty> |
        //   statement statements
        //
        //---------------------------------------------------------------------------------------
        private JsBlock ParseStatements()
        {
            var program = new JsBlock(CurrentPositionContext(), this);
            m_blockType.Add(BlockType.Block);
            m_useCurrentForNext = false;
            try
            {
                // get the first token
                GetNextToken();

                // if the block doesn't have a proper file context, then let's set it from the
                // first token -- that token might have had a ///#source directive!
                if (string.IsNullOrEmpty(program.Context.Document.FileContext))
                {
                    program.Context.Document.FileContext = m_currentToken.Document.FileContext;
                }

                m_noSkipTokenSet.Add(NoSkipTokenSet.s_StartStatementNoSkipTokenSet);
                m_noSkipTokenSet.Add(NoSkipTokenSet.s_TopLevelNoSkipTokenSet);

                try
                {
                    var possibleDirectivePrologue = true;
                    int lastEndPosition = m_currentToken.EndPosition;
                    while (m_currentToken.Token != JsToken.EndOfFile)
                    {
                        JsAstNode ast = null;
                        try
                        {
                            // parse a statement -- pass true because we really want a SourceElement,
                            // which is a Statement OR a FunctionDeclaration. Technically, FunctionDeclarations
                            // are not statements!
                            ast = ParseStatement(true);

                            // if we are still possibly looking for directive prologues
                            if (possibleDirectivePrologue)
                            {
                                var constantWrapper = ast as JsConstantWrapper;
                                if (constantWrapper != null && constantWrapper.PrimitiveType == JsPrimitiveType.String)
                                {
                                    if (!(constantWrapper is JsDirectivePrologue))
                                    {
                                        // use a directive prologue node instead
                                        ast = new JsDirectivePrologue(constantWrapper.Value.ToString(), ast.Context, ast.Parser)
                                            {
                                                MayHaveIssues = constantWrapper.MayHaveIssues
                                            };
                                    }
                                }
                                else if (!m_newModule)
                                {
                                    // nope -- no longer finding directive prologues
                                    possibleDirectivePrologue = false;
                                }
                            }
                            else if (m_newModule)
                            {
                                // we aren't looking for directive prologues anymore, but we did scan
                                // into a new module after that last AST, so reset the flag because that
                                // new module might have directive prologues for next time
                                possibleDirectivePrologue = true;
                            }
                        }
                        catch (RecoveryTokenException exc)
                        {
                            if (TokenInList(NoSkipTokenSet.s_TopLevelNoSkipTokenSet, exc)
                                || TokenInList(NoSkipTokenSet.s_StartStatementNoSkipTokenSet, exc))
                            {
                                ast = exc._partiallyComputedNode;
                                GetNextToken();
                            }
                            else
                            {
                                m_useCurrentForNext = false;
                                do
                                {
                                    GetNextToken();
                                } while (m_currentToken.Token != JsToken.EndOfFile && !TokenInList(NoSkipTokenSet.s_TopLevelNoSkipTokenSet, m_currentToken.Token)
                                  && !TokenInList(NoSkipTokenSet.s_StartStatementNoSkipTokenSet, m_currentToken.Token));
                            }
                        }

                        if (null != ast)
                        {
                            // append the token to the program
                            program.Append(ast);

                            // set the last end position to be the start of the current token.
                            // if we parse the next statement and the end is still the start, we know
                            // something is up and might get into an infinite loop.
                            lastEndPosition = m_currentToken.EndPosition;
                        }
                        else if (!m_scanner.IsEndOfFile && m_currentToken.StartLinePosition == lastEndPosition)
                        {
                            // didn't parse a statement, we're not at the EOF, and we didn't move
                            // anywhere in the input stream. If we just keep looping around, we're going
                            // to get into an infinite loop. Break it.
                            m_currentToken.HandleError(JsError.ApplicationError, true);
                            break;
                        }
                    }

                    AppendImportantComments(program);
                }
                finally
                {
                    m_noSkipTokenSet.Remove(NoSkipTokenSet.s_TopLevelNoSkipTokenSet);
                    m_noSkipTokenSet.Remove(NoSkipTokenSet.s_StartStatementNoSkipTokenSet);
                }

            }
            catch (EndOfStreamException)
            {
            }

            program.UpdateWith(CurrentPositionContext());
            return program;
        }
        private static int RelocateDirectivePrologue(JsBlock block, int insertAt, JsDirectivePrologue directivePrologue)
        {
            // skip over any important comments
            while (insertAt < block.Count && (block[insertAt] is JsImportantComment))
            {
                ++insertAt;
            }

            // if the one we want to insert is already at this spot, then we're good to go
            if (block[insertAt] != directivePrologue)
            {
                // remove it from where it is right now and insert it into the proper location
                directivePrologue.Parent.ReplaceChild(directivePrologue, null);
                block.Insert(insertAt, directivePrologue);
            }

            // and move up to the next slot
            return ++insertAt;
        }
Пример #11
0
        private JsFunctionObject ParseFunction(JsFunctionType functionType, JsContext fncCtx)
        {
            JsLookup name = null;
            JsAstNodeList formalParameters = null;
            JsBlock body = null;
            bool inExpression = (functionType == JsFunctionType.Expression);
            JsContext paramsContext = null;

            GetNextToken();

            // get the function name or make an anonymous function if in expression "position"
            if (JsToken.Identifier == m_currentToken.Token)
            {
                name = new JsLookup(m_currentToken.Clone(), this)
                    {
                        Name = m_scanner.Identifier
                    };
                GetNextToken();
            }
            else
            {
                string identifier = JsKeyword.CanBeIdentifier(m_currentToken.Token);
                if (null != identifier)
                {
                    name = new JsLookup(m_currentToken.Clone(), this)
                        {
                            Name = identifier
                        };
                    GetNextToken();
                }
                else
                {
                    if (!inExpression)
                    {
                        // if this isn't a function expression, then we need to throw an error because
                        // function DECLARATIONS always need a valid identifier name
                        ReportError(JsError.NoIdentifier, m_currentToken.Clone(), true);

                        // BUT if the current token is a left paren, we don't want to use it as the name.
                        // (fix for issue #14152)
                        if (m_currentToken.Token != JsToken.LeftParenthesis
                            && m_currentToken.Token != JsToken.LeftCurly)
                        {
                            identifier = m_currentToken.Code;
                            name = new JsLookup(CurrentPositionContext(), this)
                                {
                                    Name = identifier
                                };
                            GetNextToken();
                        }
                    }
                }
            }

            // make a new state and save the old one
            List<BlockType> blockType = m_blockType;
            m_blockType = new List<BlockType>(16);
            Dictionary<string, LabelInfo> labelTable = m_labelTable;
            m_labelTable = new Dictionary<string, LabelInfo>();

            try
            {
                // get the formal parameters
                if (JsToken.LeftParenthesis != m_currentToken.Token)
                {
                    // we expect a left paren at this point for standard cross-browser support.
                    // BUT -- some versions of IE allow an object property expression to be a function name, like window.onclick.
                    // we still want to throw the error, because it syntax errors on most browsers, but we still want to
                    // be able to parse it and return the intended results.
                    // Skip to the open paren and use whatever is in-between as the function name. Doesn't matter that it's
                    // an invalid identifier; it won't be accessible as a valid field anyway.
                    bool expandedIndentifier = false;
                    while (m_currentToken.Token != JsToken.LeftParenthesis
                        && m_currentToken.Token != JsToken.LeftCurly
                        && m_currentToken.Token != JsToken.Semicolon
                        && m_currentToken.Token != JsToken.EndOfFile)
                    {
                        name.Context.UpdateWith(m_currentToken);
                        GetNextToken();
                        expandedIndentifier = true;
                    }

                    // if we actually expanded the identifier context, then we want to report that
                    // the function name needs to be an identifier. Otherwise we didn't expand the
                    // name, so just report that we expected an open paren at this point.
                    if (expandedIndentifier)
                    {
                        name.Name = name.Context.Code;
                        name.Context.HandleError(JsError.FunctionNameMustBeIdentifier, false);
                    }
                    else
                    {
                        ReportError(JsError.NoLeftParenthesis, true);
                    }
                }

                if (m_currentToken.Token == JsToken.LeftParenthesis)
                {
                    // create the parameter list
                    formalParameters = new JsAstNodeList(m_currentToken.Clone(), this);
                    paramsContext = m_currentToken.Clone();

                    // skip the open paren
                    GetNextToken();

                    // create the list of arguments and update the context
                    while (JsToken.RightParenthesis != m_currentToken.Token)
                    {
                        String id = null;
                        m_noSkipTokenSet.Add(NoSkipTokenSet.s_FunctionDeclNoSkipTokenSet);
                        try
                        {
                            JsParameterDeclaration paramDecl = null;
                            if (JsToken.Identifier != m_currentToken.Token && (id = JsKeyword.CanBeIdentifier(m_currentToken.Token)) == null)
                            {
                                if (JsToken.LeftCurly == m_currentToken.Token)
                                {
                                    ReportError(JsError.NoRightParenthesis);
                                    break;
                                }
                                else if (JsToken.Comma == m_currentToken.Token)
                                {
                                    // We're missing an argument (or previous argument was malformed and
                                    // we skipped to the comma.)  Keep trying to parse the argument list --
                                    // we will skip the comma below.
                                    ReportError(JsError.SyntaxError, true);
                                }
                                else
                                {
                                    ReportError(JsError.SyntaxError, true);
                                    SkipTokensAndThrow();
                                }
                            }
                            else
                            {
                                if (null == id)
                                {
                                    id = m_scanner.Identifier;
                                }

                                paramDecl = new JsParameterDeclaration(m_currentToken.Clone(), this)
                                    {
                                        Name = id,
                                        Position = formalParameters.Count
                                    };
                                formalParameters.Append(paramDecl);
                                GetNextToken();
                            }

                            // got an arg, it should be either a ',' or ')'
                            if (JsToken.RightParenthesis == m_currentToken.Token)
                            {
                                break;
                            }
                            else if (JsToken.Comma == m_currentToken.Token)
                            {
                                // append the comma context as the terminator for the parameter
                                paramDecl.IfNotNull(p => p.TerminatingContext = m_currentToken.Clone());
                            }
                            else
                            {
                                // deal with error in some "intelligent" way
                                if (JsToken.LeftCurly == m_currentToken.Token)
                                {
                                    ReportError(JsError.NoRightParenthesis);
                                    break;
                                }
                                else
                                {
                                    if (JsToken.Identifier == m_currentToken.Token)
                                    {
                                        // it's possible that the guy was writing the type in C/C++ style (i.e. int x)
                                        ReportError(JsError.NoCommaOrTypeDefinitionError);
                                    }
                                    else
                                        ReportError(JsError.NoComma);
                                }
                            }

                            GetNextToken();
                        }
                        catch (RecoveryTokenException exc)
                        {
                            if (IndexOfToken(NoSkipTokenSet.s_FunctionDeclNoSkipTokenSet, exc) == -1)
                                throw;
                        }
                        finally
                        {
                            m_noSkipTokenSet.Remove(NoSkipTokenSet.s_FunctionDeclNoSkipTokenSet);
                        }
                    }

                    fncCtx.UpdateWith(m_currentToken);
                    GetNextToken();
                }

                // read the function body of non-abstract functions.
                if (JsToken.LeftCurly != m_currentToken.Token)
                    ReportError(JsError.NoLeftCurly, true);

                m_blockType.Add(BlockType.Block);
                m_noSkipTokenSet.Add(NoSkipTokenSet.s_BlockNoSkipTokenSet);
                m_noSkipTokenSet.Add(NoSkipTokenSet.s_StartStatementNoSkipTokenSet);
                try
                {
                    // parse the block locally to get the exact end of function
                    body = new JsBlock(m_currentToken.Clone(), this);
                    body.BraceOnNewLine = m_foundEndOfLine;
                    GetNextToken();

                    var possibleDirectivePrologue = true;
                    while (JsToken.RightCurly != m_currentToken.Token)
                    {
                        try
                        {
                            // function body's are SourceElements (Statements + FunctionDeclarations)
                            var statement = ParseStatement(true);
                            if (possibleDirectivePrologue)
                            {
                                var constantWrapper = statement as JsConstantWrapper;
                                if (constantWrapper != null && constantWrapper.PrimitiveType == JsPrimitiveType.String)
                                {
                                    // if it's already a directive prologues, we're good to go
                                    if (!(constantWrapper is JsDirectivePrologue))
                                    {
                                        // make the statement a directive prologue instead of a constant wrapper
                                        statement = new JsDirectivePrologue(constantWrapper.Value.ToString(), constantWrapper.Context, constantWrapper.Parser)
                                            {
                                                MayHaveIssues = constantWrapper.MayHaveIssues
                                            };
                                    }
                                }
                                else if (!m_newModule)
                                {
                                    // no longer considering constant wrappers
                                    possibleDirectivePrologue = false;
                                }
                            }
                            else if (m_newModule)
                            {
                                // we scanned into a new module -- we might find directive prologues again
                                possibleDirectivePrologue = true;
                            }

                            // add it to the body
                            body.Append(statement);
                        }
                        catch (RecoveryTokenException exc)
                        {
                            if (exc._partiallyComputedNode != null)
                            {
                                body.Append(exc._partiallyComputedNode);
                            }
                            if (IndexOfToken(NoSkipTokenSet.s_StartStatementNoSkipTokenSet, exc) == -1)
                                throw;
                        }
                    }

                    // make sure any important comments before the closing brace are kept
                    AppendImportantComments(body);

                    body.Context.UpdateWith(m_currentToken);
                    fncCtx.UpdateWith(m_currentToken);
                }
                catch (EndOfStreamException)
                {
                    // if we get an EOF here, we never had a chance to find the closing curly-brace
                    fncCtx.HandleError(JsError.UnclosedFunction, true);
                }
                catch (RecoveryTokenException exc)
                {
                    if (IndexOfToken(NoSkipTokenSet.s_BlockNoSkipTokenSet, exc) == -1)
                    {
                        exc._partiallyComputedNode = new JsFunctionObject(fncCtx, this)
                            {
                                FunctionType = (inExpression ? JsFunctionType.Expression : JsFunctionType.Declaration),
                                IdContext = name.IfNotNull(n => n.Context),
                                Name = name.IfNotNull(n => n.Name),
                                ParameterDeclarations = formalParameters,
                                ParametersContext = paramsContext,
                                Body = body
                            };
                        throw;
                    }
                }
                finally
                {
                    m_blockType.RemoveAt(m_blockType.Count - 1);
                    m_noSkipTokenSet.Remove(NoSkipTokenSet.s_StartStatementNoSkipTokenSet);
                    m_noSkipTokenSet.Remove(NoSkipTokenSet.s_BlockNoSkipTokenSet);
                }

                GetNextToken();
            }
            finally
            {
                // restore state
                m_blockType = blockType;
                m_labelTable = labelTable;
            }

            return new JsFunctionObject(fncCtx, this)
                {
                    FunctionType = functionType,
                    IdContext = name.IfNotNull(n => n.Context),
                    Name = name.IfNotNull(n => n.Name),
                    ParameterDeclarations = formalParameters,
                    ParametersContext = paramsContext,
                    Body = body
                };
        }
 public void Visit(JsDirectivePrologue node)
 {
     if (node != null)
     {
         node.Index = NextOrderIndex;
         if (node.UseStrict)
         {
             CurrentVariableScope.UseStrict = true;
         }
     }
 }
Пример #13
0
 public void Visit(JsDirectivePrologue node)
 {
     Debug.Fail("shouldn't get here");
 }
Пример #14
0
 public void Visit(JsDirectivePrologue node)
 {
     if (node != null)
     {
         // always output directive prologues that aren't strict; only output
         // the use-strict directive if we need one
         node.IsRedundant = node.UseStrict && !m_needsStrictDirective;
         if (!node.IsRedundant)
         {
             Visit((JsConstantWrapper)node);
             if (node.UseStrict)
             {
                 // just output a strict directive -- don't need one anymore
                 m_needsStrictDirective = false;
             }
         }
     }
 }
 public void Visit(JsDirectivePrologue node)
 {
     // just a string, so we don't care
 }
Пример #16
0
        private JsAstNode ParseStatement(bool fSourceElement, bool skipImportantComment = false)
        {
            JsAstNode statement = null;

            // if we want to skip important comments, now is a good time to clear anything we may
            // have picked up already.
            if (skipImportantComment)
            {
                m_importantComments.Clear();
            }

            if (m_importantComments.Count > 0
                && m_settings.PreserveImportantComments
                && m_settings.IsModificationAllowed(JsTreeModifications.PreserveImportantComments))
            {
                // we have at least one important comment before the upcoming statement.
                // pop the first important comment off the queue, return that node instead.
                // don't advance the token -- we'll probably be coming back again for the next one (if any)
                statement = new JsImportantComment(m_importantComments[0], this);
                m_importantComments.RemoveAt(0);
            }
            else
            {
                String id = null;
                var isNewModule = m_newModule;

                switch (m_currentToken.Token)
                {
                    case JsToken.EndOfFile:
                        EOFError(JsError.ErrorEndOfFile);
                        throw new EndOfStreamException(); // abort parsing, get back to the main parse routine
                    case JsToken.Semicolon:
                        // make an empty statement
                        statement = new JsEmptyStatement(m_currentToken.Clone(), this);
                        GetNextToken();
                        return statement;
                    case JsToken.RightCurly:
                        ReportError(JsError.SyntaxError);
                        SkipTokensAndThrow();
                        break;
                    case JsToken.LeftCurly:
                        return ParseBlock();
                    case JsToken.Debugger:
                        return ParseDebuggerStatement();
                    case JsToken.Var:
                    case JsToken.Const:
                    case JsToken.Let:
                        return ParseVariableStatement();
                    case JsToken.If:
                        return ParseIfStatement();
                    case JsToken.For:
                        return ParseForStatement();
                    case JsToken.Do:
                        return ParseDoStatement();
                    case JsToken.While:
                        return ParseWhileStatement();
                    case JsToken.Continue:
                        statement = ParseContinueStatement();
                        if (null == statement)
                            return new JsBlock(CurrentPositionContext(), this);
                        else
                            return statement;
                    case JsToken.Break:
                        statement = ParseBreakStatement();
                        if (null == statement)
                            return new JsBlock(CurrentPositionContext(), this);
                        else
                            return statement;
                    case JsToken.Return:
                        statement = ParseReturnStatement();
                        if (null == statement)
                            return new JsBlock(CurrentPositionContext(), this);
                        else
                            return statement;
                    case JsToken.With:
                        return ParseWithStatement();
                    case JsToken.Switch:
                        return ParseSwitchStatement();
                    case JsToken.Throw:
                        statement = ParseThrowStatement();
                        if (statement == null)
                            return new JsBlock(CurrentPositionContext(), this);
                        else
                            break;
                    case JsToken.Try:
                        return ParseTryStatement();
                    case JsToken.Function:
                        // parse a function declaration
                        JsFunctionObject function = ParseFunction(JsFunctionType.Declaration, m_currentToken.Clone());
                        function.IsSourceElement = fSourceElement;
                        return function;
                    case JsToken.Else:
                        ReportError(JsError.InvalidElse);
                        SkipTokensAndThrow();
                        break;
                    case JsToken.ConditionalCommentStart:
                        return ParseStatementLevelConditionalComment(fSourceElement);
                    case JsToken.ConditionalCompilationOn:
                        {
                            JsConditionalCompilationOn ccOn = new JsConditionalCompilationOn(m_currentToken.Clone(), this);
                            GetNextToken();
                            return ccOn;
                        }
                    case JsToken.ConditionalCompilationSet:
                        return ParseConditionalCompilationSet();
                    case JsToken.ConditionalCompilationIf:
                        return ParseConditionalCompilationIf(false);
                    case JsToken.ConditionalCompilationElseIf:
                        return ParseConditionalCompilationIf(true);
                    case JsToken.ConditionalCompilationElse:
                        {
                            JsConditionalCompilationElse elseStatement = new JsConditionalCompilationElse(m_currentToken.Clone(), this);
                            GetNextToken();
                            return elseStatement;
                        }
                    case JsToken.ConditionalCompilationEnd:
                        {
                            JsConditionalCompilationEnd endStatement = new JsConditionalCompilationEnd(m_currentToken.Clone(), this);
                            GetNextToken();
                            return endStatement;
                        }

                    default:
                        m_noSkipTokenSet.Add(NoSkipTokenSet.s_EndOfStatementNoSkipTokenSet);
                        bool exprError = false;
                        try
                        {
                            bool bAssign;
                            statement = ParseUnaryExpression(out bAssign, false);

                            // look for labels
                            if (statement is JsLookup && JsToken.Colon == m_currentToken.Token)
                            {
                                // can be a label
                                id = statement.ToString();
                                if (m_labelTable.ContainsKey(id))
                                {
                                    // there is already a label with that name. Ignore the current label
                                    ReportError(JsError.BadLabel, statement.Context.Clone(), true);
                                    id = null;
                                    GetNextToken(); // skip over ':'
                                    return new JsBlock(CurrentPositionContext(), this);
                                }
                                else
                                {
                                    var colonContext = m_currentToken.Clone();
                                    GetNextToken();
                                    int labelNestCount = m_labelTable.Count + 1;
                                    m_labelTable.Add(id, new LabelInfo(m_blockType.Count, labelNestCount));
                                    if (JsToken.EndOfFile != m_currentToken.Token)
                                    {
                                        // ignore any important comments between the label and its statement
                                        // because important comments are treated like statements, and we want
                                        // to make sure the label is attached to the right REAL statement.
                                        statement = new JsLabeledStatement(statement.Context.Clone(), this)
                                            {
                                                Label = id,
                                                ColonContext = colonContext,
                                                NestCount = labelNestCount,
                                                Statement = ParseStatement(fSourceElement, true)
                                            };
                                    }
                                    else
                                    {
                                        // end of the file!
                                        //just pass null for the labeled statement
                                        statement = new JsLabeledStatement(statement.Context.Clone(), this)
                                            {
                                                Label = id,
                                                ColonContext = colonContext,
                                                NestCount = labelNestCount
                                            };
                                    }
                                    m_labelTable.Remove(id);
                                    return statement;
                                }
                            }
                            statement = ParseExpression(statement, false, bAssign, JsToken.None);

                            // if we just started a new module and this statement happens to be an expression statement...
                            if (isNewModule && statement.IsExpression)
                            {
                                // see if it's a constant wrapper
                                var constantWrapper = statement as JsConstantWrapper;
                                if (constantWrapper != null && constantWrapper.PrimitiveType == JsPrimitiveType.String)
                                {
                                    // we found a string constant expression statement right after the start of a new
                                    // module. Let's make it a DirectivePrologue if it isn't already
                                    if (!(statement is JsDirectivePrologue))
                                    {
                                        statement = new JsDirectivePrologue(constantWrapper.Value.ToString(), constantWrapper.Context, this)
                                            {
                                                MayHaveIssues = constantWrapper.MayHaveIssues
                                            };
                                    }
                                }
                            }

                            var binaryOp = statement as JsBinaryOperator;
                            if (binaryOp != null
                                && (binaryOp.OperatorToken == JsToken.Equal || binaryOp.OperatorToken == JsToken.StrictEqual))
                            {
                                // an expression statement with equality operator? Doesn't really do anything.
                                // Did the developer intend this to be an assignment operator instead? Low-pri warning.
                                binaryOp.OperatorContext.IfNotNull(c => c.HandleError(JsError.SuspectEquality, false));
                            }

                            var lookup = statement as JsLookup;
                            if (lookup != null
                                && lookup.Name.StartsWith("<%=", StringComparison.Ordinal) && lookup.Name.EndsWith("%>", StringComparison.Ordinal))
                            {
                                // single lookup, but it's actually one or more ASP.NET blocks.
                                // convert back to an asp.net block node
                                statement = new JsAspNetBlockNode(statement.Context, this)
                                {
                                    AspNetBlockText = lookup.Name
                                };
                            }

                            var aspNetBlock = statement as JsAspNetBlockNode;
                            if (aspNetBlock != null && JsToken.Semicolon == m_currentToken.Token)
                            {
                                aspNetBlock.IsTerminatedByExplicitSemicolon = true;
                                statement.IfNotNull(s => s.TerminatingContext = m_currentToken.Clone());
                                GetNextToken();
                            }

                            // we just parsed an expression statement. Now see if we have an appropriate
                            // semicolon to terminate it.
                            if (JsToken.Semicolon == m_currentToken.Token)
                            {
                                statement.IfNotNull(s => s.TerminatingContext = m_currentToken.Clone());
                                GetNextToken();
                            }
                            else if (m_foundEndOfLine || JsToken.RightCurly == m_currentToken.Token || JsToken.EndOfFile == m_currentToken.Token)
                            {
                                // semicolon insertion rules
                                // (if there was no statement parsed, then don't fire a warning)
                                // a right-curly or an end of line is something we don't WANT to throw a warning for.
                                // Just too common and doesn't really warrant a warning (in my opinion)
                                if (statement != null
                                    && JsToken.RightCurly != m_currentToken.Token && JsToken.EndOfFile != m_currentToken.Token)
                                {
                                    ReportError(JsError.SemicolonInsertion, statement.Context.IfNotNull(c => c.FlattenToEnd()), true);
                                }
                            }
                            else
                            {
                                ReportError(JsError.NoSemicolon, true);
                            }
                        }
                        catch (RecoveryTokenException exc)
                        {
                            if (exc._partiallyComputedNode != null)
                                statement = exc._partiallyComputedNode;

                            if (statement == null)
                            {
                                m_noSkipTokenSet.Remove(NoSkipTokenSet.s_EndOfStatementNoSkipTokenSet);
                                exprError = true;
                                SkipTokensAndThrow();
                            }

                            if (IndexOfToken(NoSkipTokenSet.s_EndOfStatementNoSkipTokenSet, exc) == -1)
                            {
                                exc._partiallyComputedNode = statement;
                                throw;
                            }
                        }
                        finally
                        {
                            if (!exprError)
                                m_noSkipTokenSet.Remove(NoSkipTokenSet.s_EndOfStatementNoSkipTokenSet);
                        }
                        break;
                }
            }

            return statement;
        }
 public void Visit(JsDirectivePrologue node)
 {
     // just a string, so we don't care
 }
        public override void Visit(JsDirectivePrologue node)
        {
            if (node != null)
            {
                // if this is a minification hint, then process it now
                // and then remove it. Otherwise treat it as a directive prologue that
                // we need to preserve
                if (IsMinificationHint(node))
                {
                    node.Parent.ReplaceChild(node, null);
                }
                else
                {
                    // no need to call the base, just add it to the list
                    if (m_moduleDirectives == null)
                    {
                        m_moduleDirectives = new List<JsDirectivePrologue>();
                    }

                    m_moduleDirectives.Add(node);
                }
            }
        }