示例#1
0
      //---------------------------------------------------------------------------------------
      // ParseStatement
      //
      //  OptionalStatement:
      //    Statement |
      //    <empty>
      //
      //  Statement :
      //    Block |
      //  VariableStatement |
      //  EmptyStatement |
      //  ExpressionStatement |
      //  IfStatement |
      //  IterationStatement |
      //  ContinueStatement |
      //  BreakStatement |
      //  ReturnStatement |
      //  WithStatement |
      //  LabeledStatement |
      //  SwitchStatement |
      //  ThrowStatement |
      //  TryStatement |
      //  QualifiedDeclaration |
      //  Class |
      //  FunctionDeclaration
      //
      // IterationStatement :
      //    'for' '(' ForLoopControl ')' |                  ===> ForStatement
      //    'do' Statement 'while' '(' Expression ')' |     ===> DoStatement
      //    'while' '(' Expression ')' Statement            ===> WhileStatement
      //
      //---------------------------------------------------------------------------------------

      // ParseStatement deals with the end of statement issue (EOL vs ';') so if any of the
      // ParseXXX routine does it as well, it should return directly from the switch statement
      // without any further execution in the ParseStatement
      private AST ParseStatement(){
        AST statement = null;
        String id = null;

        switch (this.currentToken.token){
          case JSToken.EndOfFile:
            EOFError(JSError.ErrEOF);
            throw new EndOfFile(); // abort parsing, get back to the main parse routine
          case JSToken.Debugger:
            statement = new DebugBreak(this.currentToken.Clone());
            GetNextToken();
            break;
          case JSToken.Semicolon:
            // make an empty statement
            statement = new Block(this.currentToken.Clone());
            GetNextToken();
            return statement;
          case JSToken.RightCurly:
            ReportError(JSError.SyntaxError);
            SkipTokensAndThrow();
            break;
          case JSToken.LeftCurly:
            return ParseBlock();
          case JSToken.Var:
          case JSToken.Const:
            return ParseVariableStatement((FieldAttributes)0, null, this.currentToken.token);
          case JSToken.If:
            return ParseIfStatement();
          case JSToken.For:
            return ParseForStatement();
          case JSToken.Do:
            return ParseDoStatement();
          case JSToken.While:
            return ParseWhileStatement();
          case JSToken.Continue:
            statement = ParseContinueStatement();
            if (null == statement)
              return new Block(CurrentPositionContext());
            else
              return statement;
          case JSToken.Break:
            statement = ParseBreakStatement();
            if (null == statement)
              return new Block(CurrentPositionContext());
            else
              return statement;
          case JSToken.Return:
            statement = ParseReturnStatement();
            if (null == statement)
              return new Block(CurrentPositionContext());
            else
              return statement;
          case JSToken.With:
            return ParseWithStatement();
          case JSToken.Switch:
            return ParseSwitchStatement();
          case JSToken.Super:
          case JSToken.This:
            Context superCtx = this.currentToken.Clone();
            if (JSToken.LeftParen == this.scanner.PeekToken())
              statement = ParseConstructorCall(superCtx);
            else
              goto default;
            break;
          case JSToken.Throw:
            statement = ParseThrowStatement();
            if (statement == null)
              return new Block(CurrentPositionContext());
            else
              break;
          case JSToken.Try:
            return ParseTryStatement();
          case JSToken.Internal:
          case JSToken.Public:
          case JSToken.Static:
          case JSToken.Private:
          case JSToken.Protected:
          case JSToken.Abstract:
          case JSToken.Final:
            bool parsedOK;
            statement = ParseAttributes(null, false, false, out parsedOK);
            if (!parsedOK){
              statement = ParseExpression(statement, false, true, JSToken.None);
              statement = new Expression(statement.context.Clone(), statement);
              break;
            }else
              return statement;
          case JSToken.Package:
            Context packageContext = this.currentToken.Clone();
            statement = ParsePackage(packageContext);
            if (statement is Package){
              // handle common error of using import in function
              ReportError(JSError.PackageInWrongContext, packageContext, true);
              // make an empty statement
              statement = new Block(packageContext);
            }
            break;                      
          case JSToken.Interface:
          case JSToken.Class:
            return ParseClass((FieldAttributes)0, false, this.currentToken.Clone(), false, false, null);
          case JSToken.Enum:
            return ParseEnum((FieldAttributes)0, this.currentToken.Clone(), null);
          case JSToken.Function:
            return ParseFunction((FieldAttributes)0, false, this.currentToken.Clone(), false, false, false, false, null); //Parse a function as a statement
          case JSToken.Else:
            ReportError(JSError.InvalidElse);
            SkipTokensAndThrow();
            break;
          case JSToken.Import:
            // handle common error of using import in function
            ReportError(JSError.InvalidImport, true);
            // make an empty statement
            statement = new Block(this.currentToken.Clone());
            try{
              ParseImportStatement();
            }catch(RecoveryTokenException){
            }
            break;                      
          default:
            this.noSkipTokenSet.Add(NoSkipTokenSet.s_EndOfStatementNoSkipTokenSet);
            bool exprError = false;
            try{
              bool bAssign, canBeAttribute = true;
              statement = ParseUnaryExpression(out bAssign, ref canBeAttribute, false);
              if (canBeAttribute){
                // look for labels
                if (statement is Lookup){
                  if (JSToken.Colon == this.currentToken.token){
                    // can be a label
                    id = statement.ToString();
                    if (null != this.labelTable[id]){
                      // there is already a label with that name. Ignore the current label
                      ReportError(JSError.BadLabel, statement.context.Clone(), true);
                      id = null;
                      GetNextToken(); // skip over ':'
                      return new Block(CurrentPositionContext());
                    }else{
                      GetNextToken();
                      this.labelTable[id] = this.blockType.Count;
                      if (JSToken.EndOfFile != this.currentToken.token)
                        statement = ParseStatement();
                      else
                        statement = new Block(CurrentPositionContext());
                      this.labelTable.Remove(id);
                      return statement;
                    }
                  }
                }
                // look for custom attributes
                if (JSToken.Semicolon != this.currentToken.token && !this.scanner.GotEndOfLine()){
                  bool parsed;
                  statement = ParseAttributes(statement, false, false, out parsed);
                  if (parsed)
                    return statement;
                }
              }
              statement = ParseExpression(statement, false, bAssign, JSToken.None);
              statement = new Expression(statement.context.Clone(), statement);
            }catch(RecoveryTokenException exc){
              if (exc._partiallyComputedNode != null)
                statement = exc._partiallyComputedNode;

              if (statement == null){
                this.noSkipTokenSet.Remove(NoSkipTokenSet.s_EndOfStatementNoSkipTokenSet);
                exprError = true;
                SkipTokensAndThrow();
              }

              if (IndexOfToken(NoSkipTokenSet.s_EndOfStatementNoSkipTokenSet, exc) == -1){
                exc._partiallyComputedNode = statement;
                throw exc;
              }
            }finally{
              if (!exprError)
                this.noSkipTokenSet.Remove(NoSkipTokenSet.s_EndOfStatementNoSkipTokenSet);
            }
            break;
        }

        if (JSToken.Semicolon == this.currentToken.token){
          statement.context.UpdateWith(this.currentToken);
          GetNextToken();
        }else if (!this.scanner.GotEndOfLine() && JSToken.RightCurly != this.currentToken.token && JSToken.EndOfFile != this.currentToken.token)
          ReportError(JSError.NoSemicolon, true);

        return statement;
      }
        private AST ParseStatement()
        {
            AST leftHandSide = null;
            string key = null;
            switch (this.currentToken.token)
            {
                case JSToken.Super:
                case JSToken.This:
                {
                    Context superCtx = this.currentToken.Clone();
                    if (JSToken.LeftParen != this.scanner.PeekToken())
                    {
                        break;
                    }
                    leftHandSide = this.ParseConstructorCall(superCtx);
                    goto Label_04B0;
                }
                case JSToken.RightCurly:
                    this.ReportError(JSError.SyntaxError);
                    this.SkipTokensAndThrow();
                    goto Label_04B0;

                case JSToken.Enum:
                    return this.ParseEnum(FieldAttributes.PrivateScope, this.currentToken.Clone(), null);

                case JSToken.Interface:
                case JSToken.Class:
                    return this.ParseClass(FieldAttributes.PrivateScope, false, this.currentToken.Clone(), false, false, null);

                case JSToken.EndOfFile:
                    this.EOFError(JSError.ErrEOF);
                    throw new EndOfFile();

                case JSToken.If:
                    return this.ParseIfStatement();

                case JSToken.For:
                    return this.ParseForStatement();

                case JSToken.Do:
                    return this.ParseDoStatement();

                case JSToken.While:
                    return this.ParseWhileStatement();

                case JSToken.Continue:
                    leftHandSide = this.ParseContinueStatement();
                    if (leftHandSide != null)
                    {
                        return leftHandSide;
                    }
                    return new Block(this.CurrentPositionContext());

                case JSToken.Break:
                    leftHandSide = this.ParseBreakStatement();
                    if (leftHandSide != null)
                    {
                        return leftHandSide;
                    }
                    return new Block(this.CurrentPositionContext());

                case JSToken.Return:
                    leftHandSide = this.ParseReturnStatement();
                    if (leftHandSide != null)
                    {
                        return leftHandSide;
                    }
                    return new Block(this.CurrentPositionContext());

                case JSToken.Import:
                    this.ReportError(JSError.InvalidImport, true);
                    leftHandSide = new Block(this.currentToken.Clone());
                    try
                    {
                        this.ParseImportStatement();
                    }
                    catch (RecoveryTokenException)
                    {
                    }
                    goto Label_04B0;

                case JSToken.With:
                    return this.ParseWithStatement();

                case JSToken.Switch:
                    return this.ParseSwitchStatement();

                case JSToken.Throw:
                    leftHandSide = this.ParseThrowStatement();
                    if (leftHandSide != null)
                    {
                        goto Label_04B0;
                    }
                    return new Block(this.CurrentPositionContext());

                case JSToken.Try:
                    return this.ParseTryStatement();

                case JSToken.Package:
                {
                    Context packageContext = this.currentToken.Clone();
                    leftHandSide = this.ParsePackage(packageContext);
                    if (leftHandSide is Package)
                    {
                        this.ReportError(JSError.PackageInWrongContext, packageContext, true);
                        leftHandSide = new Block(packageContext);
                    }
                    goto Label_04B0;
                }
                case JSToken.Internal:
                case JSToken.Abstract:
                case JSToken.Public:
                case JSToken.Static:
                case JSToken.Private:
                case JSToken.Protected:
                case JSToken.Final:
                    bool flag;
                    leftHandSide = this.ParseAttributes(null, false, false, out flag);
                    if (flag)
                    {
                        return leftHandSide;
                    }
                    leftHandSide = this.ParseExpression(leftHandSide, false, true, JSToken.None);
                    leftHandSide = new Expression(leftHandSide.context.Clone(), leftHandSide);
                    goto Label_04B0;

                case JSToken.Var:
                case JSToken.Const:
                    return this.ParseVariableStatement(FieldAttributes.PrivateScope, null, this.currentToken.token);

                case JSToken.Function:
                    return this.ParseFunction(FieldAttributes.PrivateScope, false, this.currentToken.Clone(), false, false, false, false, null);

                case JSToken.LeftCurly:
                    return this.ParseBlock();

                case JSToken.Semicolon:
                    leftHandSide = new Block(this.currentToken.Clone());
                    this.GetNextToken();
                    return leftHandSide;

                case JSToken.Debugger:
                    leftHandSide = new DebugBreak(this.currentToken.Clone());
                    this.GetNextToken();
                    goto Label_04B0;

                case JSToken.Else:
                    this.ReportError(JSError.InvalidElse);
                    this.SkipTokensAndThrow();
                    goto Label_04B0;
            }
            this.noSkipTokenSet.Add(NoSkipTokenSet.s_EndOfStatementNoSkipTokenSet);
            bool flag2 = false;
            try
            {
                bool flag3;
                bool canBeAttribute = true;
                leftHandSide = this.ParseUnaryExpression(out flag3, ref canBeAttribute, false);
                if (canBeAttribute)
                {
                    if ((leftHandSide is Lookup) && (JSToken.Colon == this.currentToken.token))
                    {
                        key = leftHandSide.ToString();
                        if (this.labelTable[key] != null)
                        {
                            this.ReportError(JSError.BadLabel, leftHandSide.context.Clone(), true);
                            key = null;
                            this.GetNextToken();
                            return new Block(this.CurrentPositionContext());
                        }
                        this.GetNextToken();
                        this.labelTable[key] = this.blockType.Count;
                        if (this.currentToken.token != JSToken.EndOfFile)
                        {
                            leftHandSide = this.ParseStatement();
                        }
                        else
                        {
                            leftHandSide = new Block(this.CurrentPositionContext());
                        }
                        this.labelTable.Remove(key);
                        return leftHandSide;
                    }
                    if ((JSToken.Semicolon != this.currentToken.token) && !this.scanner.GotEndOfLine())
                    {
                        bool flag5;
                        leftHandSide = this.ParseAttributes(leftHandSide, false, false, out flag5);
                        if (flag5)
                        {
                            return leftHandSide;
                        }
                    }
                }
                leftHandSide = this.ParseExpression(leftHandSide, false, flag3, JSToken.None);
                leftHandSide = new Expression(leftHandSide.context.Clone(), leftHandSide);
            }
            catch (RecoveryTokenException exception)
            {
                if (exception._partiallyComputedNode != null)
                {
                    leftHandSide = exception._partiallyComputedNode;
                }
                if (leftHandSide == null)
                {
                    this.noSkipTokenSet.Remove(NoSkipTokenSet.s_EndOfStatementNoSkipTokenSet);
                    flag2 = true;
                    this.SkipTokensAndThrow();
                }
                if (this.IndexOfToken(NoSkipTokenSet.s_EndOfStatementNoSkipTokenSet, exception) == -1)
                {
                    exception._partiallyComputedNode = leftHandSide;
                    throw exception;
                }
            }
            finally
            {
                if (!flag2)
                {
                    this.noSkipTokenSet.Remove(NoSkipTokenSet.s_EndOfStatementNoSkipTokenSet);
                }
            }
        Label_04B0:
            if (JSToken.Semicolon == this.currentToken.token)
            {
                leftHandSide.context.UpdateWith(this.currentToken);
                this.GetNextToken();
                return leftHandSide;
            }
            if ((!this.scanner.GotEndOfLine() && (JSToken.RightCurly != this.currentToken.token)) && (this.currentToken.token != JSToken.EndOfFile))
            {
                this.ReportError(JSError.NoSemicolon, true);
            }
            return leftHandSide;
        }