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; } }
private static JsStatement GenerateBody(string stateVariableName, List <Node> nodes) { return(JsStatement.Switch(JsExpression.Identifier(stateVariableName), nodes.Select(n => JsStatement.SwitchSection(n.StateValues.Select(v => JsExpression.Number(v)), JsStatement.Try( n.Children.Count > 0 ? (JsStatement)JsStatement.Block(GenerateBody(stateVariableName, n.Children), JsStatement.Break()) : JsStatement.Break(), null, JsExpression.Invocation(JsExpression.Member(JsExpression.Identifier(n.HandlerName), "call"), JsExpression.This)))))); }
public void SwitchStatementWorks() { AssertCorrect(JsStatement.Switch(JsExpression.Identifier("x"), JsStatement.SwitchSection(new[] { JsExpression.Number(0) }, JsExpression.Identifier("a")), JsStatement.SwitchSection(new[] { JsExpression.Number(1), JsExpression.Number(2) }, JsExpression.Identifier("b")), JsStatement.SwitchSection(new[] { null, JsExpression.Number(3) }, JsExpression.Identifier("c")) ), "switch(x){case 0:{a;}case 1:case 2:{b;}default:case 3:{c;}}"); }
public override JsStatement VisitSwitchStatement(JsSwitchStatement statement, object data) { var oldBreak = _breakStack; var oldContinue = _continueStack; try { _breakStack = _breakStack.Push(null); _continueStack = _continueStack.Push(null); var sections = VisitSwitchSections(statement.Sections, data); return(ReferenceEquals(sections, statement.Sections) ? statement : JsStatement.Switch(statement.Expression, sections)); } finally { _breakStack = oldBreak; _continueStack = oldContinue; } }
public virtual JsStatement VisitSwitchStatement(JsSwitchStatement statement, TData data) { var test = VisitExpression(statement.Expression, data); var clauses = VisitSwitchSections(statement.Sections, data); return(ReferenceEquals(test, statement.Expression) && ReferenceEquals(clauses, statement.Sections) ? statement : JsStatement.Switch(test, clauses)); }