コード例 #1
0
 public void VariableDeclarationStatementsAreCorrectlyOutput()
 {
     AssertCorrect(JsStatement.Var(new[] { JsStatement.Declaration("i", null) }), "var i;\n");
     AssertCorrect(JsStatement.Var(new[] { JsStatement.Declaration("i", null), JsStatement.Declaration("j", null) }), "var i, j;\n");
     AssertCorrect(JsStatement.Var(new[] { JsStatement.Declaration("i", JsExpression.Number(0)) }), "var i = 0;\n");
     AssertCorrect(JsStatement.Var(new[] { JsStatement.Declaration("i", JsExpression.Number(0)), JsStatement.Declaration("j", JsExpression.Number(1)) }), "var i = 0, j = 1;\n");
     AssertCorrect(JsStatement.Var(new[] { JsStatement.Declaration("i", JsExpression.Number(0)), JsStatement.Declaration("j", null) }), "var i = 0, j;\n");
 }
コード例 #2
0
        internal JsBlockStatement Process(JsBlockStatement statement)
        {
            _allocateFinallyHandler = null;
            _makeSetCurrent         = null;
            var result      = Process(statement, false, false);
            var hoistResult = VariableHoistingVisitor.Process(result);

            return(JsStatement.Block(new[] { JsStatement.Var(new[] { JsStatement.Declaration(_stateVariableName, JsExpression.Number(0)) }.Concat(hoistResult.Item2.Select(v => JsStatement.Declaration(v, null)))) }.Concat(hoistResult.Item1.Statements)));
        }
コード例 #3
0
        private JsBlockStatement ProcessAsyncMethod(JsBlockStatement statement, string stateMachineMethodName, string doFinallyBlocksVariableName, JsVariableDeclaration taskCompletionSource, Func <JsExpression, JsExpression> makeSetResult, Func <JsExpression, JsExpression> makeSetException, Func <JsExpression> getTask, Func <JsExpression, JsExpression, JsExpression> bindToContext)
        {
            _stateMachineMethodName      = stateMachineMethodName;
            _doFinallyBlocksVariableName = doFinallyBlocksVariableName;
            _makeSetResult = taskCompletionSource != null ? makeSetResult : null;
            _needDoFinallyBlocksVariable = new HasAwaitInsideTryWithFinallyVisitor().Analyze(statement);

            var result      = Process(statement, isIteratorBlock: false, isAsync: true);
            var hoistResult = VariableHoistingVisitor.Process(result);

            string catchVariable = _allocateTempVariable();

            JsStatement body;

            if (taskCompletionSource != null && (statement.Statements.Count == 0 || IsNextStatementReachable(statement.Statements[statement.Statements.Count - 1])))                    // If we return the task, and if we risk falling out of the original method, we need to add a setResult call.
            {
                body = JsStatement.Block(hoistResult.Item1.Statements.Concat(new JsStatement[] { makeSetResult(null) }));
            }
            else
            {
                body = hoistResult.Item1;
            }

            if (taskCompletionSource != null)
            {
                body = JsStatement.Try(body, JsStatement.Catch(catchVariable, JsStatement.Block(makeSetException(JsExpression.Identifier(catchVariable)))), null);
            }

            IEnumerable <JsVariableDeclaration> declarations = new[] { JsStatement.Declaration(_stateVariableName, JsExpression.Number(0)) };

            if (taskCompletionSource != null)
            {
                declarations = declarations.Concat(new[] { taskCompletionSource });
            }
            declarations = declarations.Concat(hoistResult.Item2.Select(v => JsStatement.Declaration(v, null)));

            if (_needDoFinallyBlocksVariable)
            {
                body = JsStatement.Block(new[] { JsStatement.Var(_doFinallyBlocksVariableName, JsExpression.True) }.Concat(body is JsBlockStatement ? ((JsBlockStatement)body).Statements : (IEnumerable <JsStatement>) new[] { body }));
            }

            var stateMachine      = JsExpression.FunctionDefinition(new string[0], body);
            var boundStateMachine = UsesThisVisitor.Analyze(stateMachine.Body) ? bindToContext(stateMachine, JsExpression.This) : stateMachine;

            IEnumerable <JsStatement> stmts = new JsStatement[] { JsStatement.Var(declarations),
                                                                  JsStatement.Var(stateMachineMethodName, boundStateMachine),
                                                                  JsExpression.Invocation(JsExpression.Identifier(stateMachineMethodName)) };

            if (taskCompletionSource != null)
            {
                stmts = stmts.Concat(new[] { JsStatement.Return(getTask()) });
            }

            return(JsStatement.Block(stmts));
        }
コード例 #4
0
            public override JsVariableDeclaration VisitVariableDeclaration(JsVariableDeclaration declaration, Tuple <Dictionary <string, string>, HashSet <string> > data)
            {
                string newName;

                if (data.Item1.TryGetValue(declaration.Name, out newName))
                {
                    return(JsStatement.Declaration(newName, declaration.Initializer != null ? VisitExpression(declaration.Initializer, data) : null));
                }
                else
                {
                    return(base.VisitVariableDeclaration(declaration, data));
                }
            }
コード例 #5
0
        private IteratorStateMachine ProcessIteratorBlock(JsBlockStatement statement, Func <string> allocateFinallyHandler, Func <JsExpression, JsExpression> makeSetCurrent)
        {
            _allocateFinallyHandler = allocateFinallyHandler;
            _makeSetCurrent         = makeSetCurrent;

            var result = Process(statement, isIteratorBlock: true, isAsync: false);

            var stateFinallyHandlers = _allStates.Where(s => !s.FinallyStack.IsEmpty).Select(s => Tuple.Create(s.StateValue, s.FinallyStack.Select(x => x.Item2).Reverse().ToList())).ToList();

            var hoistResult = VariableHoistingVisitor.Process(result);

            return(new IteratorStateMachine(hoistResult.Item1,
                                            new[] { JsStatement.Declaration(_stateVariableName, JsExpression.Number(0)) }.Concat(hoistResult.Item2.Select(v => JsStatement.Declaration(v, null))),
                                            _finallyHandlers.Select(h => Tuple.Create(h.Item1, JsExpression.FunctionDefinition(new string[0], h.Item2))),
                                            stateFinallyHandlers.Count > 0 ? DisposeGenerator.GenerateDisposer(_stateVariableName, stateFinallyHandlers) : null));
        }
コード例 #6
0
        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(;;){}");
        }
コード例 #7
0
        protected void AssertCorrect(string orig, string expected, MethodType methodType = MethodType.Normal)
        {
            int tempIndex = 0, stateIndex = 0, loopLabelIndex = 0;
            var stmt = JsStatement.EnsureBlock(JavaScriptParser.Parser.ParseStatement(orig, allowCustomKeywords: true));
            JsBlockStatement result;

            if (methodType == MethodType.Iterator)
            {
                int finallyHandlerIndex = 0;
                result = StateMachineRewriter.RewriteIteratorBlock(stmt, e => e.NodeType != ExpressionNodeType.Identifier, () => "$tmp" + (++tempIndex).ToString(CultureInfo.InvariantCulture), () => "$state" + (++stateIndex).ToString(CultureInfo.InvariantCulture), () => string.Format("$loop" + (++loopLabelIndex).ToString(CultureInfo.InvariantCulture)), () => string.Format("$finally" + (++finallyHandlerIndex).ToString(CultureInfo.InvariantCulture)), v => JsExpression.Invocation(JsExpression.Identifier("setCurrent"), v), sm => {
                    var body = new List <JsStatement>();
                    if (sm.Variables.Count > 0)
                    {
                        body.Add(JsStatement.Var(sm.Variables));
                    }
                    body.AddRange(sm.FinallyHandlers.Select(h => (JsStatement)JsExpression.Assign(JsExpression.Identifier(h.Item1), h.Item2)));
                    if (sm.Disposer != null)
                    {
                        body.Add(JsExpression.Assign(JsExpression.Identifier("dispose"), JsExpression.FunctionDefinition(new string[0], sm.Disposer)));
                    }
                    body.Add(sm.MainBlock);
                    return(JsStatement.Block(body));
                });
            }
            else if (methodType == MethodType.AsyncTask || methodType == MethodType.AsyncVoid)
            {
                result = StateMachineRewriter.RewriteAsyncMethod(stmt,
                                                                 e => e.NodeType != ExpressionNodeType.Identifier,
                                                                 () => "$tmp" + (++tempIndex).ToString(CultureInfo.InvariantCulture),
                                                                 () => "$state" + (++stateIndex).ToString(CultureInfo.InvariantCulture),
                                                                 () => string.Format("$loop" + (++loopLabelIndex).ToString(CultureInfo.InvariantCulture)),
                                                                 "$sm",
                                                                 "$doFinally",
                                                                 methodType == MethodType.AsyncTask ? JsStatement.Declaration("$tcs", JsExpression.New(JsExpression.Identifier("TaskCompletionSource"))) : null,
                                                                 expr => { if (methodType != MethodType.AsyncTask)
                                                                           {
                                                                               throw new InvalidOperationException("Should not set result in async void method");
                                                                           }
                                                                           return(JsExpression.Invocation(JsExpression.Member(JsExpression.Identifier("$tcs"), "setResult"), expr ?? JsExpression.String("<<null>>"))); },
                                                                 expr => { if (methodType != MethodType.AsyncTask)
                                                                           {
                                                                               throw new InvalidOperationException("Should not set exception in async void method");
                                                                           }
                                                                           return(JsExpression.Invocation(JsExpression.Member(JsExpression.Identifier("$tcs"), "setException"), expr)); },
                                                                 () => { if (methodType != MethodType.AsyncTask)
                                                                         {
                                                                             throw new InvalidOperationException("Should not get task async void method");
                                                                         }
                                                                         return(JsExpression.Invocation(JsExpression.Member(JsExpression.Identifier("$tcs"), "getTask"))); },
                                                                 (sm, ctx) => JsExpression.Invocation(JsExpression.Identifier("$Bind"), sm, ctx));
            }
            else
            {
                result = StateMachineRewriter.RewriteNormalMethod(stmt, e => e.NodeType != ExpressionNodeType.Identifier, () => "$tmp" + (++tempIndex).ToString(CultureInfo.InvariantCulture), () => "$state" + (++stateIndex).ToString(CultureInfo.InvariantCulture), () => string.Format("$loop" + (++loopLabelIndex).ToString(CultureInfo.InvariantCulture)));
            }
            var actual = OutputFormatter.Format(result);

            Assert.That(actual.Replace("\r\n", "\n"), Is.EqualTo(expected.Replace("\r\n", "\n")), "Expected:\n" + expected + "\n\nActual:\n" + actual);
        }
コード例 #8
0
        public virtual JsVariableDeclaration VisitVariableDeclaration(JsVariableDeclaration declaration, TData data)
        {
            var after = (declaration.Initializer != null ? VisitExpression(declaration.Initializer, data) : null);

            return(ReferenceEquals(after, declaration.Initializer) ? declaration : JsStatement.Declaration(declaration.Name, after));
        }