//--------------------------------------------------------------------------------------- // 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; }