// Parse a statement. private JNode Statement() { JNode stmt = null; JNode temp, temp2; Context save; // Save the current context, so that we know // where the statement starts. save = tokenInfo.MakeCopy(); // Determine what kind of statement to parse. switch(token) { case JSToken.LeftCurly: { // Compound statement encountered. NextToken(); while(token != JSToken.RightCurly && token != JSToken.EndOfFile) { temp = Statement(); stmt = Support.CreateCompound(stmt, temp); } if(stmt == null) { stmt = new JEmpty(Context.BuildRange (save, tokenInfo)); } else if(stmt is JCompound) { // Make sure the compound statement includes // the curly brackets. stmt.context = Context.BuildRange (save, tokenInfo); } if(token == JSToken.EndOfFile) { SyntaxError("`}' expected"); } else { NextToken(); } } break; case JSToken.Semicolon: { // Bare semi-colon for an empty statement. stmt = new JEmpty(save); NextToken(); } break; case JSToken.If: { // Parse an "if" statement. NextToken(); temp = BracketedExpression(); stmt = Statement(); if(token != JSToken.Else) { stmt = new JIf(Context.BuildRange (save, stmt.context), temp, stmt, null); } else { NextToken(); temp2 = Statement(); stmt = new JIf(Context.BuildRange (save, temp2.context), temp, stmt, temp2); } } break; case JSToken.While: { // Parse a "while" statement. NextToken(); temp = BracketedExpression(); stmt = Statement(); stmt = new JWhile(Context.BuildRange (save, stmt.context), temp, stmt); } break; case JSToken.Do: { // Parse a "do" statement. NextToken(); stmt = Statement(); Expect(JSToken.While, "`while' expected"); temp = BracketedExpression(); stmt = new JDo(Context.BuildRange(save, temp.context), stmt, temp); } break; case JSToken.Continue: { // Parse a "continue" statement. NextToken(); if(HaveSemiColon()) { // Continue with no label. stmt = new JContinue(save, null); MatchSemiColon(); } else if(token == JSToken.Identifier) { // Extract the label. stmt = new JContinue (Context.BuildRange(save, tokenInfo), scanner.GetIdentifierName()); NextToken(); MatchSemiColon(); } else { SyntaxError("`continue' label expected"); } } break; case JSToken.Break: { // Parse a "break" statement. NextToken(); if(HaveSemiColon()) { // Break with no label. stmt = new JBreak(save, null); MatchSemiColon(); } else if(token == JSToken.Identifier) { // Extract the label. stmt = new JBreak (Context.BuildRange(save, tokenInfo), scanner.GetIdentifierName()); NextToken(); MatchSemiColon(); } else { SyntaxError("`break' label expected"); } } break; case JSToken.Return: { // Parse a "return" statement. NextToken(); if(HaveSemiColon()) { // Return with no expression. stmt = new JReturn(save); MatchSemiColon(); } else { // Return with an expression. temp = Expression(); stmt = new JReturnExpr (Context.BuildRange(save, temp.context), temp); MatchSemiColon(); } } break; case JSToken.Throw: { // Parse a "throw" statement. NextToken(); if(HaveSemiColon()) { // Throw with missing expression. SyntaxError("expression expected"); } else { // Parse the expression for the "throw". temp = Expression(); stmt = new JThrow (Context.BuildRange(save, temp.context), temp); MatchSemiColon(); } } break; case JSToken.With: { // Parse a "with" statement. NextToken(); temp = BracketedExpression(); stmt = Statement(); stmt = new JWith(Context.BuildRange(save, stmt.context), temp, stmt); } break; case JSToken.Var: { // Parse a variable declaration. NextToken(); stmt = VariableDeclarationList(false); MatchSemiColon(); } break; case JSToken.For: { // Parse a "for" statement. JNode init, cond, incr; NextToken(); Expect(JSToken.LeftParen, "`(' expected"); // Parse the initialization expression. if(token == JSToken.Var) { // Starts with a variable declaration. NextToken(); init = VariableDeclarationList(true); } else if(token == JSToken.Semicolon) { // No initialization expression. init = null; } else { // No variable declarations. init = ExpressionNoIn(); init = new JExprStmt (init.context.MakeCopy(), init); } // Is this the normal or "in" form? if(token != JSToken.In) { Expect(JSToken.Semicolon, "`;' expected"); if(token != JSToken.Semicolon) { cond = Expression(); } else { cond = null; } Expect(JSToken.Semicolon, "`;' expected"); if(token != JSToken.RightParen) { incr = Expression(); } else { incr = null; } Expect(JSToken.RightParen, "`)' expected"); temp = Statement(); stmt = new JFor(Context.BuildRange (save, temp.context), init, cond, incr, temp); } else { if(init is JCompound) { SyntaxError("only one variable name can be " + "used with for(var ... in ...)"); } else if(init != null && !(init is JVarDecl)) { CheckLeftHandSideExpression(init); } NextToken(); cond = Expression(); Expect(JSToken.RightParen, "`)' expected"); temp = Statement(); stmt = new JForIn(Context.BuildRange (save, temp.context), init, cond, temp); } } break; case JSToken.Switch: { // Parse a "switch" statement. NextToken(); temp = BracketedExpression(); Expect(JSToken.LeftCurly, "`{' expected"); stmt = CaseBlock(); Expect(JSToken.RightCurly, "`}' expected"); if(stmt != null) { stmt = new JSwitch(Context.BuildRange (save, stmt.context), temp, stmt); } else { // No clauses, so evaluate the expression // for its side-effects only. stmt = new JExprStmt (temp.context.MakeCopy(), temp); } } break; case JSToken.Try: { // Parse a "try" statement. String catchName = null; JNode catchClause = null; JNode finallyClause = null; NextToken(); stmt = Block(); if(token == JSToken.Catch) { NextToken(); Expect(JSToken.LeftParen, "`(' expected"); if(token != JSToken.Identifier) { SyntaxError("identifier expected"); } catchName = scanner.GetIdentifierName(); NextToken(); Expect(JSToken.RightParen, "`)' expected"); catchClause = Block(); } else if(token != JSToken.Finally) { SyntaxError("`catch' or `finally' expected"); } if(token == JSToken.Finally) { NextToken(); finallyClause = Block(); save = Context.BuildRange (save, finallyClause.context); } else { save = Context.BuildRange (save, catchClause.context); } stmt = new JTry(save, stmt, catchName, catchClause, finallyClause); } break; default: { // Should be an expression. temp = StatementExpression(); if(token == JSToken.Colon) { // The expression is followed by a colon, // so it is probably a label. if(!(temp is JIdentifier)) { SyntaxError("invalid statement label"); } NextToken(); stmt = Statement(); Support.AddLabel (((JIdentifier)temp).name, stmt); stmt.context = Context.BuildRange (save, stmt.context); } else { // Ordinary expression statement. stmt = new JExprStmt (Context.BuildRange(save, temp.context), temp); MatchSemiColon(); } } break; } // Return the statement to the caller. return stmt; }
// Parse a list of statements within a "switch" case block. private JNode CaseStatementList() { JNode stmt = null; JNode stmt2; while(token != JSToken.RightCurly && token != JSToken.Case && token != JSToken.Default) { stmt2 = Statement(); stmt = Support.CreateCompound(stmt, stmt2); } if(stmt == null) { stmt = new JEmpty(tokenInfo.MakeCopy()); } return stmt; }