Пример #1
0
        public JsStatement VisitGotoStateStatement(JsGotoStateStatement statement, object data)
        {
            var   result = new List <JsStatement>();
            State targetState;

            if (statement.TargetState == null)
            {
                if (!_labelStates.TryGetValue(statement.TargetLabel, out targetState))
                {
                    throw new InvalidOperationException("The label " + statement.TargetLabel + " does not exist.");
                }
            }
            else
            {
                targetState = statement.TargetState.Value;
            }

            var remaining = statement.CurrentState.FinallyStack;

            for (int i = 0, n = remaining.Count() - targetState.FinallyStack.Count(); i < n; i++)
            {
                var current = remaining.Peek();
                remaining = remaining.Pop();
                result.Add(JsExpression.Assign(JsExpression.Identifier(_stateVariableName), JsExpression.Number(remaining.IsEmpty ? -1 : remaining.Peek().Item1)));
                result.Add(JsExpression.Invocation(JsExpression.Member(JsExpression.Identifier(current.Item2), "call"), JsExpression.This));
            }

            result.Add(MakeSetNextStateStatement(targetState.StateValue));
            result.Add(targetState.StateValue == -1 ? (JsStatement)JsStatement.Break(targetState.LoopLabelName) : JsStatement.Continue(targetState.LoopLabelName));
            return(JsStatement.BlockMerged(result));
        }
        private static JsStatement GenerateBody(string stateVariableName, List <Node> nodes)
        {
            if (nodes.Count == 0)
            {
                return(JsStatement.Break());
            }

            return(JsStatement.Switch(JsExpression.Identifier(stateVariableName),
                                      nodes.Select(n => JsStatement.SwitchSection(n.StateValues.Select(v => JsExpression.Number(v)),
                                                                                  JsStatement.Try(
                                                                                      GenerateBody(stateVariableName, n.Children),
                                                                                      null,
                                                                                      JsExpression.Invocation(JsExpression.Member(JsExpression.Identifier(n.HandlerName), "call"), JsExpression.This))))));
        }
        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;
            }
        }
Пример #4
0
 public void BreakStatementIsCorrectlyOutput()
 {
     AssertCorrect(JsStatement.Break(), "break;\n");
     AssertCorrect(JsStatement.Break("someLabel"), "break someLabel;\n");
 }