public void Visit(LabeledStatement node)
 {
     if (node != null)
     {
         // requires a separator if the statement does
         if (node.Statement != null)
         {
             node.Statement.Accept(this);
         }
         else
         {
             DoesRequire = false;
         }
     }
 }
Exemple #2
0
 public void Visit(LabeledStatement node)
 {
     // starts with a label identifier, so we don't care
 }
 public void Visit(LabeledStatement node)
 {
     DebugEx.Fail("shouldn't get here");
 }
Exemple #4
0
        //---------------------------------------------------------------------------------------
        // ParseStatement
        //
        //  OptionalStatement:
        //    Statement |
        //    <empty>
        //
        //  Statement :
        //    Block |
        //  VariableStatement |
        //  EmptyStatement |
        //  ExpressionStatement |
        //  IfStatement |
        //  IterationStatement |
        //  ContinueStatement |
        //  BreakStatement |
        //  ReturnStatement |
        //  WithStatement |
        //  LabeledStatement |
        //  SwitchStatement |
        //  ThrowStatement |
        //  TryStatement |
        //  FunctionDeclaration
        //
        // IterationStatement :
        //    'for' '(' ForLoopControl ')' |                  ===> ForStatement
        //    'do' Statement 'while' '(' Expression ')' |     ===> DoStatement
        //    'while' '(' Expression ')' Statement            ===> WhileStatement
        //
        //---------------------------------------------------------------------------------------

        // ParseStatement deals with the end of statement issue (EOL vs ';') so if any of the
        // ParseXXX routine does it as well, it should return directly from the switch statement
        // without any further execution in the ParseStatement
        private AstNode ParseStatement(bool fSourceElement)
        {
            AstNode statement = null;
            if (m_scanner.HasImportantComments 
                && m_settings.PreserveImportantComments
                && m_settings.IsModificationAllowed(TreeModifications.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 ImportantComment(m_scanner.PopImportantComment(), this);
            }
            else
            {
                String id = null;

                switch (m_currentToken.Token)
                {
                    case JSToken.EndOfFile:
                        EOFError(JSError.ErrorEndOfFile);
                        throw new EndOfFileException(); // abort parsing, get back to the main parse routine
                    case JSToken.Semicolon:
                        // make an empty statement
                        statement = new Block(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:
                        return ParseVariableStatement((FieldAttributes)0);
                    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 Block(CurrentPositionContext(), this);
                        else
                            return statement;
                    case JSToken.Break:
                        statement = ParseBreakStatement();
                        if (null == statement)
                            return new Block(CurrentPositionContext(), this);
                        else
                            return statement;
                    case JSToken.Return:
                        statement = ParseReturnStatement();
                        if (null == statement)
                            return new Block(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 Block(CurrentPositionContext(), this);
                        else
                            break;
                    case JSToken.Try:
                        return ParseTryStatement();
                    case JSToken.Function:
                        // parse a function declaration
                        FunctionObject function = ParseFunction(FunctionType.Declaration, m_currentToken.Clone());

                        // now, if we aren't parsing source elements (directly in global scope or function body)
                        // then we want to throw a warning that different browsers will treat this function declaration
                        // differently. Technically, this location is not allowed. IE and most other browsers will 
                        // simply treat it like every other function declaration in this scope. Firefox, however, won't
                        // add this function declaration's name to the containing scope until the function declaration
                        // is actually "executed." So if you try to call it BEFORE, you will get a "not defined" error.
                        if (!fSourceElement)
                        {
                            ReportError(JSError.MisplacedFunctionDeclaration, function.IdContext, true);
                        }

                        return function;
                    case JSToken.Else:
                        ReportError(JSError.InvalidElse);
                        SkipTokensAndThrow();
                        break;
                    case JSToken.ConditionalCommentStart:
                        return ParseStatementLevelConditionalComment(fSourceElement);
                    case JSToken.ConditionalCompilationOn:
                        {
                            ConditionalCompilationOn ccOn = new ConditionalCompilationOn(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:
                        {
                            ConditionalCompilationElse elseStatement = new ConditionalCompilationElse(m_currentToken.Clone(), this);
                            GetNextToken();
                            return elseStatement;
                        }
                    case JSToken.ConditionalCompilationEnd:
                        {
                            ConditionalCompilationEnd endStatement = new ConditionalCompilationEnd(m_currentToken.Clone(), this);
                            GetNextToken();
                            return endStatement;
                        }

                    case JSToken.AspNetBlock:
                        return ParseAspNetBlock(consumeSemicolonIfPossible: true);

                    default:
                        m_noSkipTokenSet.Add(NoSkipTokenSet.s_EndOfStatementNoSkipTokenSet);
                        bool exprError = false;
                        try
                        {
                            bool bAssign;
                            // if this statement starts with a function within parens, we want to know now
                            bool parenFunction = (m_currentToken.Token == JSToken.LeftParenthesis && m_scanner.PeekToken() == JSToken.Function);
                            statement = ParseUnaryExpression(out bAssign, false);
                            if (statement != null && parenFunction)
                            {
                                FunctionObject functionObject = statement.LeftHandSide as FunctionObject;
                                if (functionObject != null)
                                {
                                    functionObject.LeftHandFunctionExpression = true;
                                }
                            }

                            // look for labels
                            if (statement is Lookup && 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 Block(CurrentPositionContext(), this);
                                }
                                else
                                {
                                    GetNextToken();
                                    int labelNestCount = m_labelTable.Count + 1;
                                    m_labelTable.Add(id, new LabelInfo(m_blockType.Count, labelNestCount));
                                    if (JSToken.EndOfFile != m_currentToken.Token)
                                    {
                                        statement = new LabeledStatement(
                                            statement.Context.Clone(),
                                            this,
                                            id,
                                            labelNestCount,
                                            ParseStatement(fSourceElement)
                                            );
                                    }
                                    else
                                    {
                                        // end of the file!
                                        //just pass null for the labeled statement
                                        statement = new LabeledStatement(
                                            statement.Context.Clone(),
                                            this,
                                            id,
                                            labelNestCount,
                                            null
                                            );
                                    }
                                    m_labelTable.Remove(id);
                                    return statement;
                                }
                            }
                            statement = ParseExpression(statement, false, bAssign, JSToken.None);
                        }
                        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;
                }

                if (JSToken.Semicolon == m_currentToken.Token)
                {
                    statement.Context.UpdateWith(m_currentToken);
                    GetNextToken();
                }
                else if (!m_scanner.GotEndOfLine && JSToken.RightCurly != m_currentToken.Token && JSToken.EndOfFile != m_currentToken.Token)
                {
                    ReportError(JSError.NoSemicolon, true);
                }
            }
            return statement;
        }
Exemple #5
0
 public void Visit(LabeledStatement node)
 {
     ReportError(node);
 }
 public void Visit(LabeledStatement node)
 {
     // invalid! ignore
     IsValid = false;
 }
Exemple #7
0
        internal override void AnalyzeNode()
        {
            // recurse
            base.AnalyzeNode();

            // we only want to remove stuff if we are hypercrunching
            if (Parser.Settings.RemoveUnneededCode)
            {
                // because we are looking at breaks, we need to know if this
                // switch statement is labeled
                string thisLabel = string.Empty;
                LabeledStatement label = Parent as LabeledStatement;
                if (label != null)
                {
                    thisLabel = label.Label;
                }

                // loop through all the cases, looking for the default.
                // then, if it's empty (or just doesn't do anything), we can
                // get rid of it altogether
                int defaultCase = -1;
                bool eliminateDefault = false;
                for (int ndx = 0; ndx < m_cases.Count; ++ndx)
                {
                    // it should always be a switch case, but just in case...
                    SwitchCase switchCase = m_cases[ndx] as SwitchCase;
                    if (switchCase != null)
                    {
                        if (switchCase.IsDefault)
                        {
                            // save the index for later
                            defaultCase = ndx;

                            // set the flag to true unless we can prove that we need it.
                            // we'll prove we need it by finding the statement block executed by
                            // this case and showing that it's neither empty nor containing
                            // just a single break statement.
                            eliminateDefault = true;
                        }

                        // if the default case is empty, then we need to keep going
                        // until we find the very next non-empty case
                        if (eliminateDefault && switchCase.Statements.Count > 0)
                        {
                            // this is the set of statements executed during default processing.
                            // if it does nothing -- one break statement -- then we can get rid
                            // of the default case. Otherwise we need to leave it in.
                            if (switchCase.Statements.Count == 1)
                            {
                                // see if it's a break
                                Break lastBreak = switchCase.Statements[0] as Break;

                                // if the last statement is not a break,
                                // OR it has a label and it's not this switch statement...
                                if (lastBreak == null
                                  || (lastBreak.Label != null && lastBreak.Label != thisLabel))
                                {
                                    // set the flag back to false to indicate that we need to keep it.
                                    eliminateDefault = false;
                                }
                            }
                            else
                            {
                                // set the flag back to false to indicate that we need to keep it.
                                eliminateDefault = false;
                            }

                            // break out of the loop
                            break;
                        }
                    }
                }

                // if we get here and the flag is still true, then either the default case is
                // empty, or it contains only a single break statement. Either way, we can get 
                // rid of it.
                if (eliminateDefault && defaultCase >= 0
                    && Parser.Settings.IsModificationAllowed(TreeModifications.RemoveEmptyDefaultCase))
                {
                    // remove it and reset the position index
                    m_cases.RemoveAt(defaultCase);
                    defaultCase = -1;
                }

                // if we have no default handling, then we know we can get rid
                // of any cases that don't do anything either.
                if (defaultCase == -1
                    && Parser.Settings.IsModificationAllowed(TreeModifications.RemoveEmptyCaseWhenNoDefault))
                {
                    // when we delete a case statement, we set this flag to true.
                    // when we hit a non-empty case statement, we set the flag to false.
                    // if we hit an empty case statement when this flag is true, we can delete this case, too.
                    bool emptyStatements = true;
                    Break deletedBreak = null;

                    // walk the tree backwards because we don't know how many we will
                    // be deleting, and if we go backwards, we won't have to adjust the 
                    // index as we go.
                    for (int ndx = m_cases.Count - 1; ndx >= 0; --ndx)
                    {
                        // should always be a switch case
                        SwitchCase switchCase = m_cases[ndx] as SwitchCase;
                        if (switchCase != null)
                        {
                            // if the block is empty and the last block was empty, we can delete this case.
                            // OR if there is only one statement and it's a break, we can delete it, too.
                            if (switchCase.Statements.Count == 0 && emptyStatements)
                            {
                                // remove this case statement because it falls through to a deleted case
                                m_cases.RemoveAt(ndx);
                            }
                            else
                            {
                                // onlyBreak will be set to null if this block is not a single-statement break block
                                Break onlyBreak = (switchCase.Statements.Count == 1 ? switchCase.Statements[0] as Break : null);
                                if (onlyBreak != null)
                                {
                                    // we'll only delete this case if the break either doesn't have a label
                                    // OR the label matches the switch statement
                                    if (onlyBreak.Label == null || onlyBreak.Label == thisLabel)
                                    {
                                        // if this is a block with only a break, then we need to keep a hold of the break
                                        // statement in case we need it later
                                        deletedBreak = onlyBreak;

                                        // remove this case statement
                                        m_cases.RemoveAt(ndx);
                                        // make sure the flag is set so we delete any other empty
                                        // cases that fell through to this empty case block
                                        emptyStatements = true;
                                    }
                                    else
                                    {
                                        // the break statement has a label and it's not the switch statement.
                                        // we're going to keep this block
                                        emptyStatements = false;
                                        deletedBreak = null;
                                    }
                                }
                                else
                                {
                                    // either this is a non-empty block, or it's an empty case that falls through
                                    // to a non-empty block. if we have been deleting case statements and this
                                    // is not an empty block....
                                    if (emptyStatements && switchCase.Statements.Count > 0 && deletedBreak != null)
                                    {
                                        // we'll need to append the deleted break statement if it doesn't already have
                                        // a flow-changing statement: break, continue, return, or throw
                                        AstNode lastStatement = switchCase.Statements[switchCase.Statements.Count - 1];
                                        if (!(lastStatement is Break) && !(lastStatement is ContinueNode)
                                          && !(lastStatement is ReturnNode) && !(lastStatement is ThrowNode))
                                        {
                                            switchCase.Statements.Append(deletedBreak);
                                        }
                                    }

                                    // make sure the deletedBreak flag is reset
                                    deletedBreak = null;

                                    // reset the flag
                                    emptyStatements = false;
                                }
                            }
                        }
                    }
                }

                // if the last case's statement list ends in a break, 
                // we can get rid of the break statement
                if (m_cases.Count > 0
                    && Parser.Settings.IsModificationAllowed(TreeModifications.RemoveBreakFromLastCaseBlock))
                {
                    SwitchCase lastCase = m_cases[m_cases.Count - 1] as SwitchCase;
                    if (lastCase != null)
                    {
                        // get the block of statements making up the last case block
                        Block lastBlock = lastCase.Statements;
                        // if the last statement is not a break, then lastBreak will be null
                        Break lastBreak = (lastBlock.Count > 0 ? lastBlock[lastBlock.Count - 1] as Break : null);
                        // if lastBreak is not null and it either has no label, or the label matches this switch statement...
                        if (lastBreak != null
                          && (lastBreak.Label == null || lastBreak.Label == thisLabel))
                        {
                            // remove the break statement
                            lastBlock.RemoveLast();
                        }
                    }
                }
            }
        }