Exemple #1
0
        public override void VisitYieldStatement(YieldStatementSyntax node)
        {
            var nextState = GetNextState(node);

            if (node.ReturnOrBreakKeyword.IsKind(SyntaxKind.BreakKeyword))
            {
                currentState.Add(ChangeState(nextState));
                currentState.Add(Cs.Return(Cs.False()));
            }
            else
            {
                currentState.Add(ChangeState(nextState));
                currentState.Add(Cs.Express(Cs.This().Member("Current").Assign(YieldThisFixer.Fix(node.Expression))));
                currentState.Add(Cs.Return(Cs.True()));
            }
            SetClosed(currentState);

            currentState = nextState;
        }
        public ClassDeclarationSyntax CreateEnumerator()
        {
            var members = new List <MemberDeclarationSyntax>();
            FieldDeclarationSyntax thisField = null;

            if (!method.IsStatic)
            {
                thisField = Cs.Field(method.ContainingType.ToTypeSyntax(), "$this");
                members.Add(thisField);
            }

            var stateGenerator = new YieldStateGenerator(compilation, node);

            stateGenerator.GenerateStates();
            var states = stateGenerator.States;

            var isStartedField = Cs.Field(Cs.Bool(), isStarted);

            members.Add(isStartedField);

            var stateField = Cs.Field(Cs.Int(), StateGenerator.state);

            members.Add(stateField);

            foreach (var parameter in node.ParameterList.Parameters)
            {
                var parameterField = Cs.Field(parameter.Type, parameter.Identifier);
                members.Add(parameterField);
            }
            foreach (var variable in stateGenerator.HoistedVariables)
            {
                var variableField = Cs.Field(variable.Item2, variable.Item1);
                members.Add(variableField);
            }

            var className = "YieldEnumerator$" + method.GetMemberName();

            var constructorParameters = new List <ParameterSyntax>();

            if (!method.IsStatic)
            {
                constructorParameters.Add(SyntaxFactory.Parameter(SyntaxFactory.Identifier("$this")).WithType(thisField.Declaration.Type));
            }
            constructorParameters.AddRange(node.ParameterList.Parameters.Select(x => SyntaxFactory.Parameter(x.Identifier).WithType(x.Type)));

            var constructor = SyntaxFactory.ConstructorDeclaration(className)
                              .AddModifiers(Cs.Public())
                              .WithParameterList(constructorParameters.ToArray())
                              .WithBody(
                SyntaxFactory.Block(
                    // Assign fields
                    constructorParameters.Select(x => Cs.Express(Cs.Assign(Cs.This().Member(x.Identifier), SyntaxFactory.IdentifierName(x.Identifier))))
                    )
                .AddStatements(
                    Cs.Express(Cs.Assign(Cs.This().Member(StateGenerator.state), Cs.Integer(1)))
                    )
                );

            members.Add(constructor);

            var elementType = ((INamedTypeSymbol)method.ReturnType).TypeArguments[0];
            var ienumerable = SyntaxFactory.ParseTypeName("System.Collections.Generic.IEnumerable<" + elementType.ToDisplayString() + ">");
            var ienumerator = SyntaxFactory.ParseTypeName("System.Collections.Generic.IEnumerator<" + elementType.ToDisplayString() + ">");

            // Generate the GetEnumerator method, which looks something like:
            // var $isStartedLocal = $isStarted;
            // $isStarted = true;
            // if ($isStartedLocal)
            //     return this.Clone().GetEnumerator();
            // else
            //     return this;
            var getEnumerator = SyntaxFactory.MethodDeclaration(ienumerator, "GetEnumerator")
                                .AddModifiers(Cs.Public(), Cs.Override())
                                .WithBody(Cs.Block(
                                              Cs.Local(isStartedLocal, SyntaxFactory.IdentifierName(isStarted)),
                                              Cs.Express(SyntaxFactory.IdentifierName(isStarted).Assign(Cs.True())),
                                              Cs.If(
                                                  SyntaxFactory.IdentifierName(isStartedLocal),
                                                  Cs.Return(Cs.This().Member("Clone").Invoke().Member("GetEnumerator").Invoke()),
                                                  Cs.Return(Cs.This()))));

            members.Add(getEnumerator);

            // Generate the MoveNext method, which looks something like:
            // $top:
            // while (true)
            // {
            //     switch (state)
            //     {
            //         case 0: ...
            //         case 1: ...
            //     }
            // }
            var moveNextBody = SyntaxFactory.LabeledStatement("$top", Cs.While(Cs.True(),
                                                                               Cs.Switch(Cs.This().Member(StateGenerator.state), states.Select((x, i) =>
                                                                                                                                               Cs.Section(Cs.Integer(i), x.Statements.ToArray())).ToArray())));
            var moveNext = SyntaxFactory.MethodDeclaration(Cs.Bool(), "MoveNext")
                           .AddModifiers(Cs.Public(), Cs.Override())
                           .WithBody(SyntaxFactory.Block(moveNextBody));

            members.Add(moveNext);

            TypeSyntax classNameWithTypeArguments = SyntaxFactory.IdentifierName(className);

            if (method.TypeParameters.Any())
            {
                classNameWithTypeArguments = SyntaxFactory.GenericName(
                    SyntaxFactory.Identifier(className),
                    SyntaxFactory.TypeArgumentList(SyntaxFactory.SeparatedList(
                                                       method.TypeParameters.Select(x => SyntaxFactory.ParseTypeName(x.Name)),
                                                       method.TypeParameters.Select(x => x).Skip(1).Select(_ => SyntaxFactory.Token(SyntaxKind.CommaToken)))
                                                   ));
            }

            var cloneBody = Cs.Block(
                Cs.Return(classNameWithTypeArguments.New(
                              constructorParameters.Select(x => SyntaxFactory.IdentifierName(x.Identifier)).ToArray()
                              ))
                );
            var clone = SyntaxFactory.MethodDeclaration(ienumerable, "Clone")
                        .AddModifiers(Cs.Public())
                        .WithBody(SyntaxFactory.Block(cloneBody));

            members.Add(clone);

            var baseTypes = new[] { SyntaxFactory.ParseTypeName("System.YieldIterator<" + elementType.ToDisplayString() + ">") };
            var result    = SyntaxFactory.ClassDeclaration(className).WithBaseList(baseTypes).WithMembers(members.ToArray());

            if (method.TypeParameters.Any())
            {
                result = result.WithTypeParameterList(node.TypeParameterList);
            }

            return(result);
        }
Exemple #3
0
        public InvocationExpressionSyntax Object(AnonymousObjectCreationExpressionSyntax obj, bool compact = false)
        {
            var method = context.JsniType.GetMembers("object").OfType <IMethodSymbol>().Single();

            return(method.Invoke(obj, compact ? Cs.True() : Cs.False()));
        }
Exemple #4
0
        public ClassDeclarationSyntax CreateStateMachine()
        {
            var members = new List <MemberDeclarationSyntax>();
            FieldDeclarationSyntax thisField = null;

            if (!method.IsStatic)
            {
                thisField = Cs.Field(method.ContainingType.ToTypeSyntax(), "$this");
                members.Add(thisField);
            }

            var stateGenerator = new AsyncStateGenerator(compilation, node);

            stateGenerator.GenerateStates();
            var states = stateGenerator.States;

            var stateField = Cs.Field(Cs.Int(), state);

            members.Add(stateField);

            var builderField = Cs.Field(Context.Instance.AsyncVoidMethodBuilder.ToTypeSyntax(), builder);

            members.Add(builderField);

            foreach (var parameter in node.ParameterList.Parameters)
            {
                var parameterField = Cs.Field(parameter.Type, parameter.Identifier);
                members.Add(parameterField);
            }
            foreach (var variable in stateGenerator.HoistedVariables)
            {
                var variableField = Cs.Field(variable.Item2, variable.Item1);
                members.Add(variableField);
            }

            var className = "Async$" + method.GetMemberName();

            var constructorParameters = new List <ParameterSyntax>();

            if (!method.IsStatic)
            {
                constructorParameters.Add(SyntaxFactory.Parameter(SyntaxFactory.Identifier("$this")).WithType(thisField.Declaration.Type));
            }
            constructorParameters.AddRange(node.ParameterList.Parameters.Select(x => SyntaxFactory.Parameter(x.Identifier).WithType(x.Type)));

            var constructor = SyntaxFactory.ConstructorDeclaration(className)
                              .AddModifiers(Cs.Public())
                              .WithParameterList(constructorParameters.ToArray())
                              .WithBody(
                SyntaxFactory.Block(
                    // Assign fields
                    constructorParameters.Select(x => Cs.Express(Cs.This().Member(x.Identifier).Assign(SyntaxFactory.IdentifierName(x.Identifier))))
                    )
                .AddStatements(
                    Cs.Express(Cs.This().Member(state).Assign(Cs.Integer(-1))),
                    Cs.Express(Cs.This().Member(builder).Assign(builderField.Declaration.Type.New())),
                    Cs.Express(Cs.This().Member(builder).Member("Start").Invoke(Cs.This()))
                    )
                );

            members.Add(constructor);

            // Generate the MoveNext method, which looks something like:
            // $top:
            // while (true)
            // {
            //     switch (state)
            //     {
            //         case 0: ...
            //         case 1: ...
            //     }
            // }
            var moveNextBody = SyntaxFactory.LabeledStatement("$top", Cs.While(Cs.True(),
                                                                               Cs.Switch(Cs.This().Member(state), states.Select((x, i) =>
                                                                                                                                Cs.Section(Cs.Integer(i), x.Statements.ToArray())).ToArray())));
            var moveNext = SyntaxFactory.MethodDeclaration(Cs.Bool(), "MoveNext")
                           .AddModifiers(Cs.Public())
                           .WithBody(SyntaxFactory.Block(moveNextBody));

            members.Add(moveNext);

            var asyncStateMachine = SyntaxFactory.ParseTypeName("System.Runtime.CompilerServices.IAsyncStateMachine");
            var baseTypes         = new[] { asyncStateMachine };
            var result            = SyntaxFactory.ClassDeclaration(className).WithBaseList(baseTypes).WithMembers(members.ToArray());

            if (method.TypeParameters.Any())
            {
                result = result.WithTypeParameterList(node.TypeParameterList);
            }

            return(result);
        }
Exemple #5
0
        public override void VisitForStatement(ForStatementSyntax node)
        {
            if (!YieldChecker.HasSpecialStatement(node))
            {
                currentState.Add(YieldThisFixer.Fix(node));
            }
            else
            {
                var semanticModel = compilation.GetSemanticModel(node.SyntaxTree);

                // Convert the variable declarations in the for loop
                if (node.Declaration != null)
                {
                    foreach (var variable in node.Declaration.Variables.Where(x => x.Initializer != null))
                    {
                        var assignment = SyntaxFactory.IdentifierName(variable.Identifier.ToString()).Assign(variable.Initializer.Value);
                        currentState.Add(Cs.Express(assignment));

                        var symbol = (ILocalSymbol)ModelExtensions.GetDeclaredSymbol(semanticModel, variable);

                        // Hoist the variable into a field
                        node = (ForStatementSyntax)HoistVariable(node, variable.Identifier, SyntaxFactory.ParseTypeName(symbol.Type.GetFullName()));
                    }
                }
                foreach (var initializer in node.Initializers)
                {
                    currentState.Add(Cs.Express(YieldThisFixer.Fix(initializer)));
                }

                MaybeCreateNewState();

                var nextState      = GetNextState(node);
                var iterationState = currentState;

                // postState determines where the flow goes after each iteration.  If there are incrementors, it goes
                // to a state that handles the incrementing, then goes back to the iteration state.  Otherwise, the
                // iteration state just points back to itself like the while loop.
                State postState;
                if (node.Incrementors.Any())
                {
                    postState           = new State(this);
                    postState.NextState = iterationState;

                    foreach (var incrementor in node.Incrementors)
                    {
                        postState.Add(Cs.Express(YieldThisFixer.Fix(incrementor)));
                    }
                    Close(postState);
                }
                else
                {
                    postState = iterationState;
                }
                iterationState.NextState  = nextState;
                iterationState.BreakState = nextState;

                var forStatement = SyntaxFactory.WhileStatement(node.Condition ?? Cs.True(), SyntaxFactory.Block(CaptureState(node.Statement, postState, nextState)));
                iterationState.Statements.Add(forStatement);

                Close(iterationState);

                currentState = nextState;
            }
        }