public override Statement ParseNoNewContext(Parser parser) { // Consume the for keyword. parser.Expect(KeywordToken.For); // Read the left parenthesis. parser.Expect(PunctuatorToken.LeftParenthesis); // The initialization statement. Statement initializationStatement = null; // The type of for statement. ForStatementType type = ForStatementType.Unknown; // The for-in and for-of expressions need a variable to assign to. Is null for a regular for statement. IReferenceExpression forInOfReference = null; if (parser.nextToken == KeywordToken.Var || parser.nextToken == KeywordToken.Let || parser.nextToken == KeywordToken.Const) { bool isVar = (parser.nextToken == KeywordToken.Var); // Read past the var/let/const token. parser.Expect(parser.nextToken); Scope scope = isVar?parser.currentVarScope : parser.currentLetScope; // There can be multiple initializers (but not for for-in statements). var varLetConstStatement = new VarStatement(scope); initializationStatement = parser.Labels(varLetConstStatement); while (true) { var declaration = new VariableDeclaration(); // The next token must be a variable name. declaration.VariableName = parser.ExpectIdentifier(); parser.ValidateVariableName(declaration.VariableName); // Add the variable to the current function's list of local variables. parser.currentVarScope.AddVariable(declaration.VariableName, null, parser.context == CodeContext.Function ? null : new LiteralExpression(Undefined.Value)); // The next token is either an equals sign (=), a semi-colon, a comma, or the "in" keyword. if (parser.nextToken == PunctuatorToken.Assignment) { // Read past the equals token (=). parser.Expect(PunctuatorToken.Assignment); // Read the setter expression. declaration.InitExpression = parser.ParseExpression(PunctuatorToken.Semicolon, PunctuatorToken.Comma); // This must be a regular for statement. type = ForStatementType.For; } // Add the declaration to the initialization statement. varLetConstStatement.Declarations.Add(declaration); if (parser.nextToken == PunctuatorToken.Semicolon) { // This is a regular for statement. break; } else if (parser.nextToken == KeywordToken.In && type == ForStatementType.Unknown) { // This is a for-in statement. forInOfReference = new NameExpression(scope, declaration.VariableName); type = ForStatementType.ForIn; break; } else if (parser.nextToken == IdentifierToken.Of && type == ForStatementType.Unknown) { // This is a for-of statement. forInOfReference = new NameExpression(scope, declaration.VariableName); type = ForStatementType.ForOf; break; } else if (parser.nextToken != PunctuatorToken.Comma) { throw new JavaScriptException(parser.engine, "SyntaxError", string.Format("Unexpected token {0}", Token.ToText(parser.nextToken)), parser.LineNumber, parser.SourcePath); } // Read past the comma token. parser.Expect(PunctuatorToken.Comma); // Multiple initializers are not allowed in for-in statements. type = ForStatementType.For; } } else { // Not a var initializer - can be a simple variable name then "in" or any expression ending with a semi-colon. // The expression can be empty. if (parser.nextToken != PunctuatorToken.Semicolon) { // Parse an expression. var initializationExpression = parser.ParseExpression(PunctuatorToken.Semicolon, KeywordToken.In, IdentifierToken.Of); // Record debug info for the expression. initializationStatement = new ExpressionStatement(initializationExpression); if (parser.nextToken == KeywordToken.In) { // This is a for-in statement. if ((initializationExpression is IReferenceExpression) == false) { throw new JavaScriptException(parser.engine, "SyntaxError", "Invalid left-hand side in for-in", parser.LineNumber, parser.SourcePath); } forInOfReference = (IReferenceExpression)initializationExpression; } else if (parser.nextToken == IdentifierToken.Of) { // This is a for-of statement. if ((initializationExpression is IReferenceExpression) == false) { throw new JavaScriptException(parser.engine, "SyntaxError", "Invalid left-hand side in for-of", parser.LineNumber, parser.SourcePath); } forInOfReference = (IReferenceExpression)initializationExpression; type = ForStatementType.ForOf; } } } if (type == ForStatementType.ForIn) { // for (x in y) // for (var x in y) var result = new ForInStatement(); var labelled = parser.Labels(result); result.Variable = forInOfReference; // Consume the "in". parser.Expect(KeywordToken.In); // Parse the right-hand-side expression. result.TargetObject = parser.ParseExpression(PunctuatorToken.RightParenthesis); // Read the right parenthesis. parser.Expect(PunctuatorToken.RightParenthesis); // Read the statements that will be executed in the loop body. result.Body = parser.ParseStatement(); return(labelled); } else if (type == ForStatementType.ForOf) { // for (x of y) // for (var x of y) var result = new ForOfStatement(); var labelled = parser.Labels(result); result.Variable = forInOfReference; // Consume the "of". parser.Expect(IdentifierToken.Of); // Parse the right-hand-side expression. result.TargetObject = parser.ParseExpression(PunctuatorToken.RightParenthesis, PunctuatorToken.Comma); // Comma is not allowed. // Read the right parenthesis. parser.Expect(PunctuatorToken.RightParenthesis); // Read the statements that will be executed in the loop body. result.Body = parser.ParseStatement(); return(labelled); } else { var result = new ForStatement(); var labelled = parser.Labels(result); // Set the initialization statement. if (initializationStatement != null) { result.InitStatement = initializationStatement; } // Read the semicolon. parser.Expect(PunctuatorToken.Semicolon); // Parse the optional condition expression. // Note: if the condition is omitted then it is considered to always be true. if (parser.nextToken != PunctuatorToken.Semicolon) { result.ConditionStatement = new ExpressionStatement(parser.ParseExpression(PunctuatorToken.Semicolon)); } // Read the semicolon. // Note: automatic semicolon insertion never inserts a semicolon in the header of a // for statement. parser.Expect(PunctuatorToken.Semicolon); // Parse the optional increment expression. if (parser.nextToken != PunctuatorToken.RightParenthesis) { result.IncrementStatement = new ExpressionStatement(parser.ParseExpression(PunctuatorToken.RightParenthesis)); } // Read the right parenthesis. parser.Expect(PunctuatorToken.RightParenthesis); // Read the statements that will be executed in the loop body. result.Body = parser.ParseStatement(); return(labelled); } }
public override Statement ParseNoNewContext(Parser parser) { var result = new SwitchStatement(); var labelled = parser.Labels(result); // Consume the switch keyword. parser.Expect(KeywordToken.Switch); // Read the left parenthesis. parser.Expect(PunctuatorToken.LeftParenthesis); // Parse the switch expression. result.Value = parser.ParseExpression(PunctuatorToken.RightParenthesis); // Read the right parenthesis. parser.Expect(PunctuatorToken.RightParenthesis); // Consume the start brace ({). parser.Expect(PunctuatorToken.LeftBrace); SwitchCase defaultClause = null; Token next = parser.nextToken; while (true) { if (next == KeywordToken.Case) { var caseClause = new SwitchCase(); // Read the case keyword. parser.Expect(KeywordToken.Case); // Parse the case expression. caseClause.Value = parser.ParseExpression(PunctuatorToken.Colon); // Consume the colon. parser.Expect(PunctuatorToken.Colon); next = parser.nextToken; // Zero or more statements can be added to the case statement. while (next != KeywordToken.Case && next != KeywordToken.Default && next != PunctuatorToken.RightBrace) { caseClause.BodyStatements.Add(parser.ParseStatement()); next = parser.nextToken; } // Add the case clause to the switch statement. result.CaseClauses.Add(caseClause); } else if (next == KeywordToken.Default) { // Make sure this is the only default clause. if (defaultClause != null) { throw new JavaScriptException(parser.engine, "SyntaxError", "Only one default clause is allowed.", parser.LineNumber, parser.SourcePath); } defaultClause = new SwitchCase(); // Read the case keyword. parser.Expect(KeywordToken.Default); // Consume the colon. parser.Expect(PunctuatorToken.Colon); next = parser.nextToken; // Zero or more statements can be added to the case statement. while (next != KeywordToken.Case && next != KeywordToken.Default && next != PunctuatorToken.RightBrace) { defaultClause.BodyStatements.Add(parser.ParseStatement()); next = parser.nextToken; } // Add the default clause to the switch statement. result.CaseClauses.Add(defaultClause); } else if (next == PunctuatorToken.RightBrace) { break; } else { // Statements cannot be added directly after the switch. throw new JavaScriptException(parser.engine, "SyntaxError", "Expected 'case' or 'default'.", parser.LineNumber, parser.SourcePath); } } // Consume the end brace. parser.Consume(); return(labelled); }