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; } } }
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"); }
//--------------------------------------------------------------------------------------- // 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; }
public void Visit(LabeledStatement node) { ReportError(node); }
public void Visit(LabeledStatement node) { // invalid! ignore IsValid = false; }
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(); } } } } }