//--------------------------------------------------------------------------------------- // ParseSwitchStatement // // SwitchStatement : // 'switch' '(' Expression ')' '{' CaseBlock '}' // // CaseBlock : // CaseList DefaultCaseClause CaseList // // CaseList : // <empty> | // CaseClause CaseList // // CaseClause : // 'case' Expression ':' OptionalStatements // // DefaultCaseClause : // <empty> | // 'default' ':' OptionalStatements //--------------------------------------------------------------------------------------- private AstNode ParseSwitchStatement() { Context switchCtx = m_currentToken.Clone(); AstNode expr = null; AstNodeList cases = null; m_blockType.Add(BlockType.Switch); try { // read switch(expr) GetNextToken(); if (JSToken.LeftParenthesis != m_currentToken.Token) ReportError(JSError.NoLeftParenthesis); GetNextToken(); m_noSkipTokenSet.Add(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet); m_noSkipTokenSet.Add(NoSkipTokenSet.s_SwitchNoSkipTokenSet); try { expr = ParseExpression(); if (JSToken.RightParenthesis != m_currentToken.Token) { ReportError(JSError.NoRightParenthesis); } GetNextToken(); if (JSToken.LeftCurly != m_currentToken.Token) { ReportError(JSError.NoLeftCurly); } GetNextToken(); } catch (RecoveryTokenException exc) { if (IndexOfToken(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet, exc) == -1 && IndexOfToken(NoSkipTokenSet.s_SwitchNoSkipTokenSet, exc) == -1) { // give up exc._partiallyComputedNode = null; throw; } else { if (exc._partiallyComputedNode == null) expr = new ConstantWrapper(true, PrimitiveType.Boolean, CurrentPositionContext(), this); else expr = exc._partiallyComputedNode; if (IndexOfToken(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet, exc) != -1) { if (exc._token == JSToken.RightParenthesis) GetNextToken(); if (JSToken.LeftCurly != m_currentToken.Token) { ReportError(JSError.NoLeftCurly); } GetNextToken(); } } } finally { m_noSkipTokenSet.Remove(NoSkipTokenSet.s_SwitchNoSkipTokenSet); m_noSkipTokenSet.Remove(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet); } // parse the switch body cases = new AstNodeList(m_currentToken.Clone(), this); bool defaultStatement = false; m_noSkipTokenSet.Add(NoSkipTokenSet.s_BlockNoSkipTokenSet); try { while (JSToken.RightCurly != m_currentToken.Token) { SwitchCase caseClause = null; AstNode caseValue = null; Context caseCtx = m_currentToken.Clone(); m_noSkipTokenSet.Add(NoSkipTokenSet.s_CaseNoSkipTokenSet); try { if (JSToken.Case == m_currentToken.Token) { // get the case GetNextToken(); caseValue = ParseExpression(); } else if (JSToken.Default == m_currentToken.Token) { // get the default if (defaultStatement) { // we report an error but we still accept the default ReportError(JSError.DupDefault, true); } else { defaultStatement = true; } GetNextToken(); } else { // This is an error, there is no case or default. Assume a default was missing and keep going defaultStatement = true; ReportError(JSError.BadSwitch); } if (JSToken.Colon != m_currentToken.Token) { ReportError(JSError.NoColon); } // read the statements inside the case or default GetNextToken(); } catch (RecoveryTokenException exc) { // right now we can only get here for the 'case' statement if (IndexOfToken(NoSkipTokenSet.s_CaseNoSkipTokenSet, exc) == -1) { // ignore the current case or default exc._partiallyComputedNode = null; throw; } else { caseValue = exc._partiallyComputedNode; if (exc._token == JSToken.Colon) { GetNextToken(); } } } finally { m_noSkipTokenSet.Remove(NoSkipTokenSet.s_CaseNoSkipTokenSet); } m_blockType.Add(BlockType.Block); try { Block statements = new Block(m_currentToken.Clone(), this); m_noSkipTokenSet.Add(NoSkipTokenSet.s_SwitchNoSkipTokenSet); m_noSkipTokenSet.Add(NoSkipTokenSet.s_StartStatementNoSkipTokenSet); try { while (JSToken.RightCurly != m_currentToken.Token && JSToken.Case != m_currentToken.Token && JSToken.Default != m_currentToken.Token) { try { // parse a Statement, not a SourceElement statements.Append(ParseStatement(false)); } catch (RecoveryTokenException exc) { if (exc._partiallyComputedNode != null) { statements.Append(exc._partiallyComputedNode); exc._partiallyComputedNode = null; } if (IndexOfToken(NoSkipTokenSet.s_StartStatementNoSkipTokenSet, exc) == -1) { throw; } } } } catch (RecoveryTokenException exc) { if (IndexOfToken(NoSkipTokenSet.s_SwitchNoSkipTokenSet, exc) == -1) { caseClause = new SwitchCase(caseCtx, this, caseValue, statements); cases.Append(caseClause); throw; } } finally { m_noSkipTokenSet.Remove(NoSkipTokenSet.s_StartStatementNoSkipTokenSet); m_noSkipTokenSet.Remove(NoSkipTokenSet.s_SwitchNoSkipTokenSet); } if (JSToken.RightCurly == m_currentToken.Token) { statements.Context.UpdateWith(m_currentToken); } caseCtx.UpdateWith(statements.Context); caseClause = new SwitchCase(caseCtx, this, caseValue, statements); cases.Append(caseClause); } finally { m_blockType.RemoveAt(m_blockType.Count - 1); } } } catch (RecoveryTokenException exc) { if (IndexOfToken(NoSkipTokenSet.s_BlockNoSkipTokenSet, exc) == -1) { //save what you can a rethrow switchCtx.UpdateWith(CurrentPositionContext()); exc._partiallyComputedNode = new Switch(switchCtx, this, expr, cases); throw; } } finally { m_noSkipTokenSet.Remove(NoSkipTokenSet.s_BlockNoSkipTokenSet); } switchCtx.UpdateWith(m_currentToken); GetNextToken(); } finally { m_blockType.RemoveAt(m_blockType.Count - 1); } return new Switch(switchCtx, this, expr, cases); }