Exemplo n.º 1
0
        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);
            }
        }
Exemplo n.º 2
0
        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);
        }