public void Visit(ForIn node) { if (node != null) { node.Index = NextOrderIndex; if (node.Collection != null) { node.Collection.Accept(this); } if (node.Variable != null) { // if the variable portion of the for-in statement is a lexical // declaration, then we will create the block node for its body right now // and add the declaration. This will prevent the body from deleting // an empty lexical scope. var lexDeclaration = node.Variable as LexicalDeclaration; if (lexDeclaration != null) { // create the scope on the block node.BlockScope = new BlockScope(CurrentLexicalScope, node.Context, m_settings) { IsInWithScope = m_withDepth > 0 }; m_lexicalStack.Push(node.BlockScope); } } try { if (node.Variable != null) { node.Variable.Accept(this); } if (node.Body != null) { node.Body.Accept(this); } } finally { if (node.BlockScope != null) { Debug.Assert(CurrentLexicalScope == node.BlockScope); m_lexicalStack.Pop(); } } } }
public void Visit(ForIn node) { // invalid! ignore IsValid = false; }
public void Visit(ForIn node) { Debug.Fail("shouldn't get here"); }
public void Visit(ForIn node) { // not applicable; terminate }
private AstNode ParseForStatement() { m_blockType.Add(BlockType.Loop); AstNode forNode = null; try { Context forCtx = m_currentToken.Clone(); GetNextToken(); if (JSToken.LeftParenthesis != m_currentToken.Token) { ReportError(JSError.NoLeftParenthesis); } GetNextToken(); bool isForIn = false, recoveryInForIn = false; AstNode lhs = null, initializer = null, condOrColl = null, increment = null; Context operatorContext = null; Context separator1Context = null; Context separator2Context = null; try { if (JSToken.Var == m_currentToken.Token || JSToken.Let == m_currentToken.Token || JSToken.Const == m_currentToken.Token) { isForIn = true; Declaration declaration; if (m_currentToken.Token == JSToken.Var) { declaration = new Var(m_currentToken.Clone(), this); } else { declaration = new LexicalDeclaration(m_currentToken.Clone(), this) { StatementToken = m_currentToken.Token }; } declaration.Append(ParseIdentifierInitializer(JSToken.In)); // a list of variable initializers is allowed only in a for(;;) while (JSToken.Comma == m_currentToken.Token) { isForIn = false; declaration.Append(ParseIdentifierInitializer(JSToken.In)); //initializer = new Comma(initializer.context.CombineWith(var.context), initializer, var); } initializer = declaration; // if it could still be a for..in, now it's time to get the 'in' // TODO: for ES6 might be 'of' if (isForIn) { if (JSToken.In == m_currentToken.Token || (m_currentToken.Token == JSToken.Identifier && string.CompareOrdinal(m_currentToken.Code, "of") == 0)) { operatorContext = m_currentToken.Clone(); GetNextToken(); condOrColl = ParseExpression(); } else { isForIn = false; } } } else { if (JSToken.Semicolon != m_currentToken.Token) { bool isLHS; initializer = ParseUnaryExpression(out isLHS, false); if (isLHS && (JSToken.In == m_currentToken.Token || (m_currentToken.Token == JSToken.Identifier && string.CompareOrdinal(m_currentToken.Code, "of") == 0))) { isForIn = true; operatorContext = m_currentToken.Clone(); lhs = initializer; initializer = null; GetNextToken(); m_noSkipTokenSet.Add(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet); try { condOrColl = ParseExpression(); } catch (RecoveryTokenException exc) { if (IndexOfToken(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet, exc) == -1) { exc._partiallyComputedNode = null; throw; } else { if (exc._partiallyComputedNode == null) condOrColl = new ConstantWrapper(true, PrimitiveType.Boolean, CurrentPositionContext(), this); // what could we put here? else condOrColl = exc._partiallyComputedNode; } if (exc._token == JSToken.RightParenthesis) { GetNextToken(); recoveryInForIn = true; } } finally { m_noSkipTokenSet.Remove(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet); } } else { initializer = ParseExpression(initializer, false, isLHS, JSToken.In); } } } } catch (RecoveryTokenException exc) { // error is too early abort for exc._partiallyComputedNode = null; throw; } // at this point we know whether or not is a for..in if (isForIn) { if (!recoveryInForIn) { if (JSToken.RightParenthesis != m_currentToken.Token) ReportError(JSError.NoRightParenthesis); forCtx.UpdateWith(m_currentToken); GetNextToken(); } AstNode body = null; // if the statements aren't withing curly-braces, throw a possible error if (JSToken.LeftCurly != m_currentToken.Token) { ReportError(JSError.StatementBlockExpected, CurrentPositionContext(), true); } try { // parse a Statement, not a SourceElement body = ParseStatement(false); } catch (RecoveryTokenException exc) { if (exc._partiallyComputedNode == null) body = new Block(CurrentPositionContext(), this); else body = exc._partiallyComputedNode; exc._partiallyComputedNode = new ForIn(forCtx, this) { Variable = (lhs != null ? lhs : initializer), OperatorContext = operatorContext, Collection = condOrColl, Body = AstNode.ForceToBlock(body), }; throw; } // for (a in b) // lhs = a, initializer = null // for (var a in b) // lhs = null, initializer = var a forNode = new ForIn(forCtx, this) { Variable = (lhs != null ? lhs : initializer), OperatorContext = operatorContext, Collection = condOrColl, Body = AstNode.ForceToBlock(body), }; } else { m_noSkipTokenSet.Add(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet); try { if (JSToken.Semicolon == m_currentToken.Token) { separator1Context = m_currentToken.Clone(); } else { ReportError(JSError.NoSemicolon); if (JSToken.Colon == m_currentToken.Token) { m_noSkipTokenSet.Add(NoSkipTokenSet.s_VariableDeclNoSkipTokenSet); try { SkipTokensAndThrow(); } catch (RecoveryTokenException) { if (JSToken.Semicolon == m_currentToken.Token) { m_useCurrentForNext = false; } else { throw; } } finally { m_noSkipTokenSet.Remove(NoSkipTokenSet.s_VariableDeclNoSkipTokenSet); } } } GetNextToken(); if (JSToken.Semicolon != m_currentToken.Token) { condOrColl = ParseExpression(); if (JSToken.Semicolon != m_currentToken.Token) { ReportError(JSError.NoSemicolon); } } separator2Context = m_currentToken.Clone(); GetNextToken(); if (JSToken.RightParenthesis != m_currentToken.Token) { increment = ParseExpression(); } if (JSToken.RightParenthesis != m_currentToken.Token) { ReportError(JSError.NoRightParenthesis); } forCtx.UpdateWith(m_currentToken); GetNextToken(); } catch (RecoveryTokenException exc) { if (IndexOfToken(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet, exc) == -1) { exc._partiallyComputedNode = null; throw; } else { // discard any partial info, just genrate empty condition and increment and keep going exc._partiallyComputedNode = null; if (condOrColl == null) condOrColl = new ConstantWrapper(true, PrimitiveType.Boolean, CurrentPositionContext(), this); } if (exc._token == JSToken.RightParenthesis) { GetNextToken(); } } finally { m_noSkipTokenSet.Remove(NoSkipTokenSet.s_BlockConditionNoSkipTokenSet); } // if this is an assignment, throw a warning in case the developer // meant to use == instead of = // but no warning if the condition is wrapped in parens. var binOp = condOrColl as BinaryOperator; if (binOp != null && binOp.OperatorToken == JSToken.Assign) { condOrColl.Context.HandleError(JSError.SuspectAssignment); } AstNode body = null; // if the statements aren't withing curly-braces, throw a possible error if (JSToken.LeftCurly != m_currentToken.Token) { ReportError(JSError.StatementBlockExpected, CurrentPositionContext(), true); } try { // parse a Statement, not a SourceElement body = ParseStatement(false); } catch (RecoveryTokenException exc) { if (exc._partiallyComputedNode == null) body = new Block(CurrentPositionContext(), this); else body = exc._partiallyComputedNode; exc._partiallyComputedNode = new ForNode(forCtx, this) { Initializer = initializer, Separator1Context = separator1Context, Condition = condOrColl, Separator2Context = separator2Context, Incrementer = increment, Body = AstNode.ForceToBlock(body) }; throw; } forNode = new ForNode(forCtx, this) { Initializer = initializer, Separator1Context = separator1Context, Condition = condOrColl, Separator2Context = separator2Context, Incrementer = increment, Body = AstNode.ForceToBlock(body) }; } } finally { m_blockType.RemoveAt(m_blockType.Count - 1); } return forNode; }
public override void Visit(ForIn node) { if (node != null) { // if this forIn-statement has it's own lexical scope, then it's an error // if the any of the field names declared in this scope is also defined inside the body. if (node.BlockScope != null) { foreach (var field in node.BlockScope.LexicallyDeclaredNames) { // if the block has a lexical scope, check it for conflicts if (node.Body != null && node.Body.BlockScope != null) { var lexDecl = node.Body.BlockScope.LexicallyDeclaredName(field.Name); if (lexDecl != null) { // report the error (lex/const/funcdecl collision) lexDecl.NameContext.HandleError(JSError.DuplicateLexicalDeclaration, true); // link the inner one to the outer one so any renaming stays in sync. if (lexDecl.VariableField != null) { lexDecl.VariableField.OuterField = field.VariableField; if (field.VariableField != null && !lexDecl.VariableField.CanCrunch) { field.VariableField.CanCrunch = false; } } } } // check to make sure there are no var-decl'd names with the same name. Those will // get carried up to this scope so we don't need to check the block scope (if any) var varDecl = node.BlockScope.VarDeclaredName(field.Name); if (varDecl != null) { // report the error (lex/const collides with var) or warning (funcdecl collides with var) varDecl.NameContext.HandleError(JSError.DuplicateLexicalDeclaration, field is LexicalDeclaration); // and mark them both as no-rename varDecl.VariableField.IfNotNull(v => v.CanCrunch = false); field.VariableField.IfNotNull(v => v.CanCrunch = false); } } } // if we are stripping debugger statements and the body is // just a debugger statement, replace it with a null // (but only if the body doesn't have its own lexical scope) if (m_parser.Settings.StripDebugStatements && m_parser.Settings.IsModificationAllowed(TreeModifications.StripDebugStatements) && node.Body != null && node.Body.BlockScope == null && node.Body.IsDebuggerStatement) { node.Body = null; } // recurse base.Visit(node); // if the body is now empty (and doesn't have its own lexical scope), make it null if (node.Body != null && node.Body.Count == 0 && node.Body.BlockScope == null) { node.Body = null; } } }