//--------------------------------------------------------------------------------------- // ParseForStatement // // ForStatement : // 'for' '(' OptionalExpressionNoIn ';' OptionalExpression ';' OptionalExpression ')' // 'for' '(' 'var' VariableDeclarationListNoIn ';' OptionalExpression ';' OptionalExpression ')' // 'for' '(' LeftHandSideExpression 'in' Expression')' // 'for' '(' 'var' Identifier OptionalInitializerNoIn 'in' Expression')' // // OptionalExpressionNoIn : // <empty> | // ExpressionNoIn // same as Expression but does not process 'in' as an operator // // OptionalInitializerNoIn : // <empty> | // InitializerNoIn // same as initializer but does not process 'in' as an operator //--------------------------------------------------------------------------------------- private AST ParseForStatement(){ this.blockType.Add(BlockType.Loop); AST forNode = null; try{ Context forCtx = this.currentToken.Clone(); GetNextToken(); if (JSToken.LeftParen != this.currentToken.token) ReportError(JSError.NoLeftParen); GetNextToken(); bool isForIn = false, recoveryInForIn = false; AST lhs = null, initializer = null, condOrColl = null, increment = null; try{ if (JSToken.Var == this.currentToken.token){ isForIn = true; initializer = ParseIdentifierInitializer(JSToken.In, (FieldAttributes)0, null, JSToken.Var); // a list of variable initializers is allowed only in a for(;;) AST var = null; while (JSToken.Comma == this.currentToken.token){ isForIn = false; var = ParseIdentifierInitializer(JSToken.In, (FieldAttributes)0, null, JSToken.Var); initializer = new Comma(initializer.context.CombineWith(var.context), initializer, var); } // if it could still be a for..in, now it's time to get the 'in' if (isForIn){ if (JSToken.In == this.currentToken.token){ GetNextToken(); condOrColl = ParseExpression(); }else isForIn = false; } }else{ if (JSToken.Semicolon != this.currentToken.token){ bool isLHS; initializer = ParseUnaryExpression(out isLHS, false); if (isLHS && JSToken.In == this.currentToken.token){ isForIn = true; lhs = initializer; initializer = null; GetNextToken(); this.noSkipTokenSet.Add(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet); try{ condOrColl = ParseExpression(); }catch(RecoveryTokenException exc){ if (IndexOfToken(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet, exc) == -1){ exc._partiallyComputedNode = null; throw exc; }else{ if (exc._partiallyComputedNode == null) condOrColl = new ConstantWrapper(true, CurrentPositionContext()); // what could we put here? else condOrColl = exc._partiallyComputedNode; } if (exc._token == JSToken.RightParen){ GetNextToken(); recoveryInForIn = true; } }finally{ this.noSkipTokenSet.Remove(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet); } }else initializer = ParseExpression(initializer, false, isLHS, JSToken.In); }else initializer = new EmptyLiteral(CurrentPositionContext()); } }catch(RecoveryTokenException exc){ // error is too early abort for exc._partiallyComputedNode = null; throw exc; } // at this point we know whether or not is a for..in if (isForIn){ if (!recoveryInForIn){ if (JSToken.RightParen != this.currentToken.token) ReportError(JSError.NoRightParen); forCtx.UpdateWith(this.currentToken); GetNextToken(); } AST body = null; try{ body = ParseStatement(); }catch(RecoveryTokenException exc){ if (exc._partiallyComputedNode == null) body = new Block(CurrentPositionContext()); else body = exc._partiallyComputedNode; exc._partiallyComputedNode = new ForIn(forCtx, lhs, initializer, condOrColl, body); throw exc; } forNode = new ForIn(forCtx, lhs, initializer, condOrColl, body); }else{ this.noSkipTokenSet.Add(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet); try{ if (JSToken.Semicolon != this.currentToken.token){ ReportError(JSError.NoSemicolon); if (JSToken.Colon == this.currentToken.token){ this.noSkipTokenSet.Add(NoSkipTokenSet.s_VariableDeclNoSkipTokenSet); try{ SkipTokensAndThrow(); }catch(RecoveryTokenException exc){ if (JSToken.Semicolon == this.currentToken.token) this.errorToken = null; else throw exc; }finally{ this.noSkipTokenSet.Remove(NoSkipTokenSet.s_VariableDeclNoSkipTokenSet); } } } GetNextToken(); if (JSToken.Semicolon != this.currentToken.token){ condOrColl = ParseExpression(); if (JSToken.Semicolon != this.currentToken.token) ReportError(JSError.NoSemicolon); }else condOrColl = new ConstantWrapper(true, CurrentPositionContext()); GetNextToken(); if (JSToken.RightParen != this.currentToken.token) increment = ParseExpression(); else increment = new EmptyLiteral(CurrentPositionContext()); if (JSToken.RightParen != this.currentToken.token) ReportError(JSError.NoRightParen); forCtx.UpdateWith(this.currentToken); GetNextToken(); }catch(RecoveryTokenException exc){ if (IndexOfToken(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet, exc) == -1){ exc._partiallyComputedNode = null; throw exc; }else{ // discard any partial info, just genrate empty condition and increment and keep going exc._partiallyComputedNode = null; if (condOrColl == null) condOrColl = new ConstantWrapper(true, CurrentPositionContext()); if (increment == null) increment = new EmptyLiteral(CurrentPositionContext()); } if (exc._token == JSToken.RightParen){ GetNextToken(); } }finally{ this.noSkipTokenSet.Remove(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet); } AST body = null; try{ body = ParseStatement(); }catch(RecoveryTokenException exc){ if (exc._partiallyComputedNode == null) body = new Block(CurrentPositionContext()); else body = exc._partiallyComputedNode; exc._partiallyComputedNode = new For(forCtx, initializer, condOrColl, increment, body); throw exc; } forNode = new For(forCtx, initializer, condOrColl, increment, body); } }finally{ this.blockType.RemoveAt(this.blockType.Count - 1); } return forNode; }
private AST ParseForStatement() { this.blockType.Add(BlockType.Loop); AST ast = null; try { Context context = this.currentToken.Clone(); this.GetNextToken(); if (JSToken.LeftParen != this.currentToken.token) { this.ReportError(JSError.NoLeftParen); } this.GetNextToken(); bool flag = false; bool flag2 = false; AST var = null; AST ast3 = null; AST collection = null; AST incrementer = null; try { if (JSToken.Var == this.currentToken.token) { flag = true; ast3 = this.ParseIdentifierInitializer(JSToken.In, FieldAttributes.PrivateScope, null, JSToken.Var); AST ast6 = null; while (JSToken.Comma == this.currentToken.token) { flag = false; ast6 = this.ParseIdentifierInitializer(JSToken.In, FieldAttributes.PrivateScope, null, JSToken.Var); ast3 = new Comma(ast3.context.CombineWith(ast6.context), ast3, ast6); } if (flag) { if (JSToken.In == this.currentToken.token) { this.GetNextToken(); collection = this.ParseExpression(); } else { flag = false; } } } else if (JSToken.Semicolon != this.currentToken.token) { bool flag3; ast3 = this.ParseUnaryExpression(out flag3, false); if (flag3 && (JSToken.In == this.currentToken.token)) { flag = true; var = ast3; ast3 = null; this.GetNextToken(); this.noSkipTokenSet.Add(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet); try { try { collection = this.ParseExpression(); } catch (RecoveryTokenException exception) { if (this.IndexOfToken(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet, exception) == -1) { exception._partiallyComputedNode = null; throw exception; } if (exception._partiallyComputedNode == null) { collection = new ConstantWrapper(true, this.CurrentPositionContext()); } else { collection = exception._partiallyComputedNode; } if (exception._token == JSToken.RightParen) { this.GetNextToken(); flag2 = true; } } goto Label_01E1; } finally { this.noSkipTokenSet.Remove(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet); } } ast3 = this.ParseExpression(ast3, false, flag3, JSToken.In); } else { ast3 = new EmptyLiteral(this.CurrentPositionContext()); } } catch (RecoveryTokenException exception2) { exception2._partiallyComputedNode = null; throw exception2; } Label_01E1: if (flag) { if (!flag2) { if (JSToken.RightParen != this.currentToken.token) { this.ReportError(JSError.NoRightParen); } context.UpdateWith(this.currentToken); this.GetNextToken(); } AST ast7 = null; try { ast7 = this.ParseStatement(); } catch (RecoveryTokenException exception3) { if (exception3._partiallyComputedNode == null) { ast7 = new Block(this.CurrentPositionContext()); } else { ast7 = exception3._partiallyComputedNode; } exception3._partiallyComputedNode = new ForIn(context, var, ast3, collection, ast7); throw exception3; } return new ForIn(context, var, ast3, collection, ast7); } this.noSkipTokenSet.Add(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet); try { if (JSToken.Semicolon != this.currentToken.token) { this.ReportError(JSError.NoSemicolon); if (JSToken.Colon == this.currentToken.token) { this.noSkipTokenSet.Add(NoSkipTokenSet.s_VariableDeclNoSkipTokenSet); try { this.SkipTokensAndThrow(); } catch (RecoveryTokenException exception4) { if (JSToken.Semicolon != this.currentToken.token) { throw exception4; } this.errorToken = null; } finally { this.noSkipTokenSet.Remove(NoSkipTokenSet.s_VariableDeclNoSkipTokenSet); } } } this.GetNextToken(); if (JSToken.Semicolon != this.currentToken.token) { collection = this.ParseExpression(); if (JSToken.Semicolon != this.currentToken.token) { this.ReportError(JSError.NoSemicolon); } } else { collection = new ConstantWrapper(true, this.CurrentPositionContext()); } this.GetNextToken(); if (JSToken.RightParen != this.currentToken.token) { incrementer = this.ParseExpression(); } else { incrementer = new EmptyLiteral(this.CurrentPositionContext()); } if (JSToken.RightParen != this.currentToken.token) { this.ReportError(JSError.NoRightParen); } context.UpdateWith(this.currentToken); this.GetNextToken(); } catch (RecoveryTokenException exception5) { if (this.IndexOfToken(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet, exception5) == -1) { exception5._partiallyComputedNode = null; throw exception5; } exception5._partiallyComputedNode = null; if (collection == null) { collection = new ConstantWrapper(true, this.CurrentPositionContext()); } if (incrementer == null) { incrementer = new EmptyLiteral(this.CurrentPositionContext()); } if (exception5._token == JSToken.RightParen) { this.GetNextToken(); } } finally { this.noSkipTokenSet.Remove(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet); } AST body = null; try { body = this.ParseStatement(); } catch (RecoveryTokenException exception6) { if (exception6._partiallyComputedNode == null) { body = new Block(this.CurrentPositionContext()); } else { body = exception6._partiallyComputedNode; } exception6._partiallyComputedNode = new For(context, ast3, collection, incrementer, body); throw exception6; } ast = new For(context, ast3, collection, incrementer, body); } finally { this.blockType.RemoveAt(this.blockType.Count - 1); } return ast; }