Пример #1
0
        // 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;
                }
            }
        }
Пример #2
0
        // 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);
            }
            }
        }