// Parse a single statement ast.Statement ParseSingleStatement() { var bmk = t.GetBookmark(); // Special handling for labels if (t.token == Token.identifier) { string label = t.identifier; t.Next(); if (t.SkipOptional(Token.colon)) { return new ast.StatementLabel(bmk, label); } t.Rewind(bmk); } switch (t.token) { case Token.semicolon: { t.Compiler.RecordWarning(t.GetBookmark(), "unnecessary semicolon"); t.Next(); return null; } case Token.openBrace: { t.Next(); var stmt = new ast.StatementBlock(t.GetBookmark()); while (!t.SkipOptional(Token.closeBrace)) { stmt.AddStatement(ParseSingleStatement()); } return stmt; } case Token.kw_debugger: { t.Next(); t.SkipRequired(Token.semicolon); return new ast.StatementDebugger(bmk, Token.kw_debugger); } case Token.kw_return: { t.Next(); if (t.SkipOptional(Token.semicolon)) { return new ast.StatementReturnThrow(bmk, Token.kw_return); } else { var temp=new ast.StatementReturnThrow(bmk, Token.kw_return, ParseCompositeExpression(0)); t.SkipRequired(Token.semicolon); return temp; } } case Token.kw_throw: { t.Next(); var temp = new ast.StatementReturnThrow(bmk, Token.kw_throw, ParseCompositeExpression(0)); t.SkipRequired(Token.semicolon); return temp; } case Token.kw_fallthrough: { // Fake statement - comment // fall through Token op = t.token; t.Next(); return new ast.StatementBreakContinue(bmk, op, null); } case Token.kw_break: case Token.kw_continue: { // Statement Token op = t.token; t.Next(); // Optional label if (!t.SkipOptional(Token.semicolon)) { t.Require(Token.identifier); var temp = new ast.StatementBreakContinue(bmk, op, t.identifier); t.Next(); t.Require(Token.semicolon); return temp; } // No label return new ast.StatementBreakContinue(bmk, op, null); } case Token.kw_if: { t.Next(); // Condition t.SkipRequired(Token.openRound); var stmt=new ast.StatementIfElse(bmk, ParseCompositeExpression(0)); t.SkipRequired(Token.closeRound); // True code block stmt.TrueStatement=ParseStatement(); // Optional else block if (t.SkipOptional(Token.kw_else)) { stmt.FalseStatement=ParseStatement(); } return stmt; } case Token.kw_switch: { t.Next(); // Value t.SkipRequired(Token.openRound); var stmt = new ast.StatementSwitch(bmk, ParseCompositeExpression(0)); t.SkipRequired(Token.closeRound); // Opening brace t.SkipRequired(Token.openBrace); // Parse all cases ast.StatementSwitch.Case currentCase = null; while (t.token!=Token.closeBrace) { // new case? if (t.SkipOptional(Token.kw_case)) { currentCase = stmt.AddCase(ParseCompositeExpression(0)); t.SkipRequired(Token.colon); continue; } // default case? if (t.SkipOptional(Token.kw_default)) { currentCase = stmt.AddCase(null); t.SkipRequired(Token.colon); continue; } // Must have a case if (currentCase == null) { throw new CompileError("Unexpected code in switch statement before 'case' or 'default'", t); } currentCase.AddCode(ParseSingleStatement()); } // Done t.SkipRequired(Token.closeBrace); return stmt; } case Token.kw_for: { // Statement t.Next(); t.SkipRequired(Token.openRound); ast.Statement init = null; if (t.token != Token.semicolon) { // Initializers init = ParseVarDeclStatement(ParseContext.DisableInOperator | ParseContext.AllowCompositeExpressions); // Foreach iterator if (t.SkipOptional(Token.kw_in)) { var stmtForEach = new ast.StatementForIn(bmk); var decl = init as ast.StatementVariableDeclaration; if (decl != null) { if (decl.HasInitialValue()) { throw new CompileError("Syntax error - unexpected initializer in for-in statement", t); } if (decl.Variables.Count > 1) { throw new CompileError("Syntax error - unexpected multiple iterator variables in for-in statement", t); } stmtForEach.VariableDeclaration = init; } else { var exprstmtForEach = init as ast.StatementExpression; if (exprstmtForEach == null) { throw new CompileError("Syntax error - invalid iterator variable declarations in for loop", t); } if ((exprstmtForEach.Expression.RootNode as ast.ExprNodeIdentifier) == null && (exprstmtForEach.Expression.RootNode as ast.ExprNodeIndexer) == null) { throw new CompileError("Syntax error - invalid iterator variable declarations in for loop", t); } stmtForEach.Iterator = exprstmtForEach.Expression; } // Collection stmtForEach.Collection = ParseCompositeExpression(0); t.SkipRequired(Token.closeRound); // Parse content stmtForEach.Code = ParseStatement(); return stmtForEach; } } // Create the statement, store the initialization expression(s) var stmt = new ast.StatementFor(bmk); stmt.Initialize = init; t.SkipRequired(Token.semicolon); // Condition if (t.token!=Token.semicolon) stmt.Condition = ParseCompositeExpression(0); t.SkipRequired(Token.semicolon); // Iterator if (t.token!=Token.closeRound) stmt.Increment = ParseCompositeExpression(ParseContext.AllowCompositeExpressions); t.SkipRequired(Token.closeRound); // Parse code block stmt.Code = ParseStatement(); return stmt; } case Token.kw_do: { var stmt = new ast.StatementDoWhile(bmk); t.Next(); stmt.Code = ParseStatement(); t.SkipRequired(Token.kw_while); t.SkipRequired(Token.openRound); stmt.Condition = ParseCompositeExpression(ParseContext.AllowCompositeExpressions); t.SkipRequired(Token.closeRound); t.SkipRequired(Token.semicolon); return stmt; } case Token.kw_while: { var stmt = new ast.StatementWhile(bmk); t.Next(); t.SkipRequired(Token.openRound); stmt.Condition = ParseCompositeExpression(ParseContext.AllowCompositeExpressions); t.SkipRequired(Token.closeRound); stmt.Code = ParseStatement(); return stmt; } case Token.kw_with: { var stmt = new ast.StatementWith(bmk); t.Next(); t.SkipRequired(Token.openRound); stmt.Expression = ParseCompositeExpression(0); t.SkipRequired(Token.closeRound); stmt.Code = ParseStatement(); return stmt; } case Token.kw_try: { t.Next(); // Create the statement var stmt = new ast.StatementTryCatchFinally(bmk); // The code t.Require(Token.openBrace); stmt.Code = ParseStatementBlock(TriState.Yes); // Catch clauses bmk = t.GetBookmark(); while (t.SkipOptional(Token.kw_catch)) { var cc=new ast.CatchClause(bmk); // Catch expression t.SkipRequired(Token.openRound); // Exception variable name t.Require(Token.identifier); cc.ExceptionVariable=t.identifier; t.Next(); // Optional 'if <condition>' (firefox extension) if (t.token==Token.kw_if) { t.Next(); cc.Condition=ParseCompositeExpression(0); } // End of expression t.SkipRequired(Token.closeRound); // Code block t.Require(Token.openBrace); cc.Code=ParseStatementBlock(TriState.Yes); stmt.CatchClauses.Add(cc); bmk = t.GetBookmark(); } // Finally if (t.SkipOptional(Token.kw_finally)) { t.Require(Token.openBrace); stmt.FinallyClause = ParseStatementBlock(TriState.Yes); } return stmt; } case Token.kw_function: { // Function declaration t.Next(); t.Require(Token.identifier); var stmt = new ast.StatementExpression(bmk, new ast.Expression(ParseFunction())); t.SkipOptional(Token.semicolon); return stmt; } case Token.directive_comment: { var stmt = new ast.StatementComment(bmk, t.RawToken.Substring(0,2) + t.RawToken.Substring(3)); t.Next(); return stmt; } case Token.directive_private: case Token.directive_public: { var stmt = new ast.StatementAccessibility(bmk); foreach (var symbol in t.identifier.Split(',')) { var spec = new AccessibilitySpec(); if (!spec.Parse(t.token==Token.directive_private ? Accessibility.Private : Accessibility.Public, symbol)) { throw new CompileError(string.Format("Invalid private member declaration - `{0}`", symbol), t); } stmt.Specs.Add(spec); } t.Next(); return stmt; } default: { // Must be a variable declaration or an expression var stmt = ParseVarDeclStatement(0); t.SkipRequired(Token.semicolon); return stmt; } } }
// Parse a single statement ast.Statement ParseSingleStatement() { var bmk = t.GetBookmark(); // Special handling for labels if (t.token == Token.identifier) { string label = t.identifier; t.Next(); if (t.SkipOptional(Token.colon)) { return(new ast.StatementLabel(bmk, label)); } t.Rewind(bmk); } switch (t.token) { case Token.semicolon: { t.Compiler.RecordWarning(t.GetBookmark(), "unnecessary semicolon"); t.Next(); return(null); } case Token.openBrace: { t.Next(); var stmt = new ast.StatementBlock(t.GetBookmark()); while (!t.SkipOptional(Token.closeBrace)) { stmt.AddStatement(ParseSingleStatement()); } return(stmt); } case Token.kw_debugger: { t.Next(); t.SkipRequired(Token.semicolon); return(new ast.StatementDebugger(bmk, Token.kw_debugger)); } case Token.kw_return: { t.Next(); if (t.SkipOptional(Token.semicolon)) { return(new ast.StatementReturnThrow(bmk, Token.kw_return)); } else { var temp = new ast.StatementReturnThrow(bmk, Token.kw_return, ParseCompositeExpression(0)); t.SkipRequired(Token.semicolon); return(temp); } } case Token.kw_throw: { t.Next(); var temp = new ast.StatementReturnThrow(bmk, Token.kw_throw, ParseCompositeExpression(0)); t.SkipRequired(Token.semicolon); return(temp); } case Token.kw_fallthrough: { // Fake statement - comment // fall through Token op = t.token; t.Next(); return(new ast.StatementBreakContinue(bmk, op, null)); } case Token.kw_break: case Token.kw_continue: { // Statement Token op = t.token; t.Next(); // Optional label if (!t.SkipOptional(Token.semicolon)) { t.Require(Token.identifier); var temp = new ast.StatementBreakContinue(bmk, op, t.identifier); t.Next(); t.Require(Token.semicolon); return(temp); } // No label return(new ast.StatementBreakContinue(bmk, op, null)); } case Token.kw_if: { t.Next(); // Condition t.SkipRequired(Token.openRound); var stmt = new ast.StatementIfElse(bmk, ParseCompositeExpression(0)); t.SkipRequired(Token.closeRound); // True code block stmt.TrueStatement = ParseStatement(); // Optional else block if (t.SkipOptional(Token.kw_else)) { stmt.FalseStatement = ParseStatement(); } return(stmt); } case Token.kw_switch: { t.Next(); // Value t.SkipRequired(Token.openRound); var stmt = new ast.StatementSwitch(bmk, ParseCompositeExpression(0)); t.SkipRequired(Token.closeRound); // Opening brace t.SkipRequired(Token.openBrace); // Parse all cases ast.StatementSwitch.Case currentCase = null; while (t.token != Token.closeBrace) { // new case? if (t.SkipOptional(Token.kw_case)) { currentCase = stmt.AddCase(ParseCompositeExpression(0)); t.SkipRequired(Token.colon); continue; } // default case? if (t.SkipOptional(Token.kw_default)) { currentCase = stmt.AddCase(null); t.SkipRequired(Token.colon); continue; } // Must have a case if (currentCase == null) { throw new CompileError("Unexpected code in switch statement before 'case' or 'default'", t); } currentCase.AddCode(ParseSingleStatement()); } // Done t.SkipRequired(Token.closeBrace); return(stmt); } case Token.kw_for: { // Statement t.Next(); t.SkipRequired(Token.openRound); ast.Statement init = null; if (t.token != Token.semicolon) { // Initializers init = ParseVarDeclStatement(ParseContext.DisableInOperator | ParseContext.AllowCompositeExpressions); // Foreach iterator if (t.SkipOptional(Token.kw_in)) { var stmtForEach = new ast.StatementForIn(bmk); var decl = init as ast.StatementVariableDeclaration; if (decl != null) { if (decl.HasInitialValue()) { throw new CompileError("Syntax error - unexpected initializer in for-in statement", t); } if (decl.Variables.Count > 1) { throw new CompileError("Syntax error - unexpected multiple iterator variables in for-in statement", t); } stmtForEach.VariableDeclaration = init; } else { var exprstmtForEach = init as ast.StatementExpression; if (exprstmtForEach == null) { throw new CompileError("Syntax error - invalid iterator variable declarations in for loop", t); } if ((exprstmtForEach.Expression.RootNode as ast.ExprNodeIdentifier) == null && (exprstmtForEach.Expression.RootNode as ast.ExprNodeIndexer) == null) { throw new CompileError("Syntax error - invalid iterator variable declarations in for loop", t); } stmtForEach.Iterator = exprstmtForEach.Expression; } // Collection stmtForEach.Collection = ParseCompositeExpression(0); t.SkipRequired(Token.closeRound); // Parse content stmtForEach.Code = ParseStatement(); return(stmtForEach); } } // Create the statement, store the initialization expression(s) var stmt = new ast.StatementFor(bmk); stmt.Initialize = init; t.SkipRequired(Token.semicolon); // Condition if (t.token != Token.semicolon) { stmt.Condition = ParseCompositeExpression(0); } t.SkipRequired(Token.semicolon); // Iterator if (t.token != Token.closeRound) { stmt.Increment = ParseCompositeExpression(ParseContext.AllowCompositeExpressions); } t.SkipRequired(Token.closeRound); // Parse code block stmt.Code = ParseStatement(); return(stmt); } case Token.kw_do: { var stmt = new ast.StatementDoWhile(bmk); t.Next(); stmt.Code = ParseStatement(); t.SkipRequired(Token.kw_while); t.SkipRequired(Token.openRound); stmt.Condition = ParseCompositeExpression(ParseContext.AllowCompositeExpressions); t.SkipRequired(Token.closeRound); t.SkipRequired(Token.semicolon); return(stmt); } case Token.kw_while: { var stmt = new ast.StatementWhile(bmk); t.Next(); t.SkipRequired(Token.openRound); stmt.Condition = ParseCompositeExpression(ParseContext.AllowCompositeExpressions); t.SkipRequired(Token.closeRound); stmt.Code = ParseStatement(); return(stmt); } case Token.kw_with: { var stmt = new ast.StatementWith(bmk); t.Next(); t.SkipRequired(Token.openRound); stmt.Expression = ParseCompositeExpression(0); t.SkipRequired(Token.closeRound); stmt.Code = ParseStatement(); return(stmt); } case Token.kw_try: { t.Next(); // Create the statement var stmt = new ast.StatementTryCatchFinally(bmk); // The code t.Require(Token.openBrace); stmt.Code = ParseStatementBlock(TriState.Yes); // Catch clauses bmk = t.GetBookmark(); while (t.SkipOptional(Token.kw_catch)) { var cc = new ast.CatchClause(bmk); // Catch expression t.SkipRequired(Token.openRound); // Exception variable name t.Require(Token.identifier); cc.ExceptionVariable = t.identifier; t.Next(); // Optional 'if <condition>' (firefox extension) if (t.token == Token.kw_if) { t.Next(); cc.Condition = ParseCompositeExpression(0); } // End of expression t.SkipRequired(Token.closeRound); // Code block t.Require(Token.openBrace); cc.Code = ParseStatementBlock(TriState.Yes); stmt.CatchClauses.Add(cc); bmk = t.GetBookmark(); } // Finally if (t.SkipOptional(Token.kw_finally)) { t.Require(Token.openBrace); stmt.FinallyClause = ParseStatementBlock(TriState.Yes); } return(stmt); } case Token.kw_function: { // Function declaration t.Next(); t.Require(Token.identifier); var stmt = new ast.StatementExpression(bmk, new ast.Expression(ParseFunction())); t.SkipOptional(Token.semicolon); return(stmt); } case Token.directive_comment: { var stmt = new ast.StatementComment(bmk, t.RawToken.Substring(0, 2) + t.RawToken.Substring(3)); t.Next(); return(stmt); } case Token.directive_private: case Token.directive_public: { var stmt = new ast.StatementAccessibility(bmk); foreach (var symbol in t.identifier.Split(',')) { var spec = new AccessibilitySpec(); if (!spec.Parse(t.token == Token.directive_private ? Accessibility.Private : Accessibility.Public, symbol)) { throw new CompileError(string.Format("Invalid private member declaration - `{0}`", symbol), t); } stmt.Specs.Add(spec); } t.Next(); return(stmt); } default: { // Must be a variable declaration or an expression var stmt = ParseVarDeclStatement(0); t.SkipRequired(Token.semicolon); return(stmt); } } }