private Tuple <List <JsStatement>, int> ProcessInner(JsBlockStatement statement, ImmutableStack <Tuple <string, State> > breakStack, ImmutableStack <Tuple <string, State> > continueStack, ImmutableStack <Tuple <int, string> > finallyStack, int?parentState) { var oldLoopLabel = _currentLoopLabel; var oldRemainingBlocks = _remainingBlocks; try { _currentLoopLabel = _allocateLoopLabel(); _remainingBlocks = new Queue <RemainingBlock>(); _remainingBlocks.Enqueue(new RemainingBlock(ImmutableStack <StackEntry> .Empty.Push(new StackEntry(statement, 0)), breakStack, continueStack, CreateNewStateValue(finallyStack), new State(_currentLoopLabel, -1, finallyStack))); if (_exitState == null) { _exitState = new State(_currentLoopLabel, -1, ImmutableStack <Tuple <int, string> > .Empty); } var sections = new List <Section>(); int iterationCount = 0; while (_remainingBlocks.Count > 0) { var current = _remainingBlocks.Dequeue(); var list = Handle(current.Stack, current.BreakStack, current.ContinueStack, current.StateValue, current.ReturnState, _isIteratorBlock || _isAsync, true); // Merge all top-level blocks that should be merged with their parents. list = list.SelectMany(stmt => (stmt is JsBlockStatement && ((JsBlockStatement)stmt).MergeWithParent) ? ((JsBlockStatement)stmt).Statements : (IList <JsStatement>) new[] { stmt }).ToList(); sections.Add(new Section(current.StateValue, list)); if (iterationCount++ > 100000) { throw new Exception("Infinite loop when rewriting method to a state machine"); } } if (parentState != null && _isAsync) { List <int> childStates; if (!_childStates.TryGetValue(parentState.Value, out childStates)) { _childStates[parentState.Value] = childStates = new List <int>(); } childStates.AddRange(sections.Select(s => s.State.StateValue)); } var body = new List <JsStatement> { JsStatement.Label(_currentLoopLabel, JsStatement.For(JsStatement.Empty, null, null, JsStatement.Switch(JsExpression.Identifier(_stateVariableName), sections.Select(b => JsStatement.SwitchSection( GetAllContainedStateValues(b.State.StateValue).OrderBy(v => v).Select(v => JsExpression.Number(v)), JsStatement.Block(b.Statements))) .Concat(new[] { JsStatement.SwitchSection(new JsExpression[] { null }, JsStatement.Break(_currentLoopLabel)) })))) }; return(Tuple.Create(body, sections[0].State.StateValue)); } finally { _currentLoopLabel = oldLoopLabel; _remainingBlocks = oldRemainingBlocks; } }
public virtual JsStatement VisitForStatement(JsForStatement statement, TData data) { var initStatement = statement.InitStatement != null?VisitStatement(statement.InitStatement, data) : null; var condition = statement.ConditionExpression != null?VisitExpression(statement.ConditionExpression, data) : null; var iterator = statement.IteratorExpression != null?VisitExpression(statement.IteratorExpression, data) : null; var body = VisitStatement(statement.Body, data); return(ReferenceEquals(initStatement, statement.InitStatement) && ReferenceEquals(condition, statement.ConditionExpression) && ReferenceEquals(iterator, statement.IteratorExpression) && ReferenceEquals(body, statement.Body) ? statement : JsStatement.For(initStatement, condition, iterator, body)); }
public override JsStatement VisitForStatement(JsForStatement statement, object data) { var initStatement = statement.InitStatement != null?VisitStatement(statement.InitStatement, data) : null; var condition = statement.ConditionExpression != null?VisitExpression(statement.ConditionExpression, data) : null; var iterator = statement.IteratorExpression != null?VisitExpression(statement.IteratorExpression, data) : null; var body = VisitStatement(statement.Body, data); if (initStatement is JsBlockStatement) // Will happen if the init statement is a variable declaration without initializers. { Debug.Assert(((JsBlockStatement)initStatement).Statements.Count == 0); initStatement = JsStatement.Empty; } return(ReferenceEquals(initStatement, statement.InitStatement) && ReferenceEquals(condition, statement.ConditionExpression) && ReferenceEquals(iterator, statement.IteratorExpression) && ReferenceEquals(body, statement.Body) ? statement : JsStatement.For(initStatement, condition, iterator, body)); }
public void ForStatementsAreCorrectlyOutput() { AssertCorrect(JsStatement.For(JsStatement.Var("i", JsExpression.Number(0)), JsExpression.Lesser(JsExpression.Identifier("i"), JsExpression.Number(10)), JsExpression.PostfixPlusPlus(JsExpression.Identifier("i")), JsStatement.EmptyBlock), "for(var i=0;i<10;i++){}"); AssertCorrect(JsStatement.For(JsExpression.Assign(JsExpression.Identifier("i"), JsExpression.Number(0)), JsExpression.Lesser(JsExpression.Identifier("i"), JsExpression.Number(10)), JsExpression.PostfixPlusPlus(JsExpression.Identifier("i")), JsStatement.EmptyBlock), "for(i=0;i<10;i++){}"); AssertCorrect(JsStatement.For(JsStatement.Var(JsStatement.Declaration("i", JsExpression.Number(0)), JsStatement.Declaration("j", JsExpression.Number(1))), JsExpression.Lesser(JsExpression.Identifier("i"), JsExpression.Number(10)), JsExpression.Comma(JsExpression.PostfixPlusPlus(JsExpression.Identifier("i")), JsExpression.PostfixPlusPlus(JsExpression.Identifier("j"))), JsStatement.EmptyBlock), "for(var i=0,j=1;i<10;i++,j++){}"); AssertCorrect(JsStatement.For(JsStatement.Empty, null, null, JsStatement.EmptyBlock), "for(;;){}"); }
public override JsStatement VisitForStatement(JsForStatement statement, object data) { var body = VisitLoopBody(statement.Body, data); return(ReferenceEquals(body, statement.Body) ? statement : JsStatement.For(statement.InitStatement, statement.ConditionExpression, statement.IteratorExpression, body)); }