Exemplo n.º 1
0
        static async Task <SyntaxNode> GenerateStateMachineCode(Document document, StateMachineModel model, CancellationToken cancellationToken)
        {
            var funicularGeneratorsReferenced = document.FunicularGeneratorsReferenced();

            var documentRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            documentRoot = AddBaseInterfaceIfNotExists(documentRoot, model.BaseInterfaceName);

            foreach (var vertex in model.VertexClasses)
            {
                documentRoot = AddVertexClassDeclarationIfNotExists(documentRoot, vertex, model.BaseInterfaceName);
            }

            documentRoot = AddBaseParameterInterfaceIfNotExists(documentRoot, model.ParameterInterfaceName);
            documentRoot = AddParameterTypeIfNotExists(documentRoot, model.OuterParameterClassName);

            documentRoot = GenerateStateClassesRewriter.UpdateStateClasses(documentRoot, model);

            documentRoot = AddOrUpdateStateEnum(documentRoot, model, funicularGeneratorsReferenced);
            documentRoot = AddOrUpdateTriggerEnum(documentRoot, model, funicularGeneratorsReferenced);

            documentRoot = UpdateTransitionMethods(documentRoot, model);

            documentRoot = AddOrUpdateTransitionResultClass(documentRoot, model);
            documentRoot = AddOrUpdateExtensionClass(documentRoot, model, funicularGeneratorsReferenced);
            return(documentRoot);
        }
Exemplo n.º 2
0
        static SyntaxNode AddOrUpdateTriggerEnum(SyntaxNode documentRoot, StateMachineModel names,
                                                 bool addUnionTypeAttribute)
        {
            var nestedEnumTypeName = StateMachineModel.NestedEnumTypeName;
            var enumMemberNames    = names.VertexClasses.SelectMany(v => v.Transitions.Select(t => t.MethodName)).Distinct();

            return(AddOrUpdateEnumClass(documentRoot, names.OuterTriggerClassName, nestedEnumTypeName, enumMemberNames, addUnionTypeAttribute));
        }
Exemplo n.º 3
0
        static SyntaxNode AddOrUpdateStateEnum(SyntaxNode documentRoot, StateMachineModel names,
                                               bool addUnionTypeAttribute)
        {
            var stateClassName     = names.OuterStateClassName;
            var nestedEnumTypeName = StateMachineModel.NestedEnumTypeName;
            var enumMemberNames    = names.VertexClasses.Select(v => v.StateName);

            return(AddOrUpdateEnumClass(documentRoot, stateClassName, nestedEnumTypeName, enumMemberNames, addUnionTypeAttribute));
        }
Exemplo n.º 4
0
 static MethodDeclarationSyntax GenerateDoTransitionMethod(StateMachineModel names)
 {
     return(GenerateApplyMethod(
                methodName: StateMachineModel.DoTransitionMethodName,
                names: names,
                returnType: SyntaxFactory.ParseTypeName(names.TransitionResultClassName),
                generateSwitchStatement: (vertex, transition, baseTypeParameterName, parameterParameterName) => SyntaxFactory.ParseStatement(
                    $"return new {names.TransitionResultTransitionClassName}({baseTypeParameterName}, (({vertex.ClassName}){baseTypeParameterName}).{transition.MethodName}(({transition.FullParameterClassName}){parameterParameterName}), {parameterParameterName});")
                , generateDefaultStatement: (vertex, baseTypeParamName, parameterParamName) => SyntaxFactory.ParseStatement($"return new {names.TransitionResultInvalidTriggerClassName}({baseTypeParamName}, {parameterParamName});")));
 }
Exemplo n.º 5
0
        static MethodDeclarationSyntax GenerateApplyMethod(StateMachineModel names)
        {
            var returnType = SyntaxFactory.ParseTypeName(names.BaseInterfaceName);

            return(GenerateApplyMethod(
                       methodName: StateMachineModel.ApplyMethodName,
                       names: names,
                       returnType: returnType,
                       generateSwitchStatement: (vertex, transition, baseTypeParameterName, parameterParameterName) => SyntaxFactory.ParseStatement(
                           $"return (({vertex.ClassName}){baseTypeParameterName}).{transition.MethodName}(({transition.FullParameterClassName}){parameterParameterName});")
                       , generateDefaultStatement: (vertex, baseTypeParamName, parameterParamName) => SyntaxFactory.ParseStatement($"return {baseTypeParamName};")));
        }
Exemplo n.º 6
0
        static bool TryParseDotGraph(string dotFileName, out StateMachineModel model)
        {
            try
            {
                var graph = AntlrParserAdapter <string> .GetParser().Parse(File.ReadAllText(dotFileName));

                model = new StateMachineModel(dotFileName, graph);
                return(true);
            }
            catch (Exception)
            {
                model = null;
                return(false);
            }
        }
Exemplo n.º 7
0
        static SyntaxNode UpdateTransitionMethods(SyntaxNode documentRoot, StateMachineModel names)
        {
            var outerParameterClass = names.TryGetOuterParameterClass(documentRoot).GetValueOrThrow();

            foreach (var _ in names.VertexClasses
                     .SelectMany(vertex => vertex.Transitions.Select(transition => new { vertex, transition })))
            {
                var parameterClass           = outerParameterClass.TryGetFirstDescendant <ClassDeclarationSyntax>(n => n.Name() == _.transition.NestedParameterClassName).GetValueOrThrow();
                var parameterClassProperties = parameterClass.DescendantNodes()
                                               .OfType <PropertyDeclarationSyntax>()
                                               .Where(p => p.Type.Name() != names.OuterTriggerClassName)
                                               .ToImmutableList();
                var vertexClass = _.vertex.TryGetVertexClass(documentRoot).GetValueOrThrow();

                var origOverloadWithFlattenedParams = _.transition.TryGetTransitionMethod(vertexClass, false);

                var overloadWithFlattenedParams = origOverloadWithFlattenedParams.GetValueOrDefault(() =>
                                                                                                    SyntaxFactory.MethodDeclaration(
                                                                                                        SyntaxFactory.ParseTypeName(_.transition.ReturnType), _.transition.MethodName)
                                                                                                    .Public()
                                                                                                    .WithBody(SyntaxFactory.Block()
                                                                                                              .AddStatements(SyntaxFactory.ParseStatement($"return new {_.transition.ReturnType}();"))
                                                                                                              ))
                                                  .WithParameterList(SyntaxFactory.ParameterList(new SeparatedSyntaxList <ParameterSyntax>().AddRange(
                                                                                                     parameterClassProperties.Select(p =>
                                                                                                                                     SyntaxFactory.Parameter(SyntaxFactory.ParseToken(p.Identifier.ToString().ToParameterName())).WithType(p.Type))
                                                                                                     ))
                                                                     );

                var newVertexClass = vertexClass.AddOrUpdateNode(origOverloadWithFlattenedParams, overloadWithFlattenedParams);

                var origOverloadWithParamClass = _.transition.TryGetTransitionMethod(newVertexClass, true);
                var overloadWithParamClass     = origOverloadWithParamClass.GetValueOrDefault(() => SyntaxFactory.MethodDeclaration(
                                                                                                  SyntaxFactory.ParseTypeName(_.transition.ReturnType), _.transition.MethodName)
                                                                                              .AddParameterListParameters(SyntaxFactory.Parameter(SyntaxFactory.ParseToken(StateMachineModel.ParametersParameterName))
                                                                                                                          .WithType(SyntaxFactory.ParseTypeName(_.transition.FullParameterClassName)))
                                                                                              .Public()
                                                                                              .WithBody(SyntaxFactory.Block())
                                                                                              ).WithBody(SyntaxFactory.Block(
                                                                                                             SyntaxFactory.ParseStatement($"return {_.transition.MethodName}({string.Join(",", parameterClassProperties.Select(p => $"{StateMachineModel.ParametersParameterName}.{p.Identifier.ToString()}"))});")
                                                                                                             ));
                newVertexClass = newVertexClass.AddOrUpdateNode(origOverloadWithParamClass, overloadWithParamClass);

                documentRoot = documentRoot.ReplaceNode(vertexClass, newVertexClass);
            }
            return(documentRoot);
        }
Exemplo n.º 8
0
        static SyntaxNode AddOrUpdateExtensionClass(SyntaxNode documentRoot, StateMachineModel names, bool funicularGeneratorsReferenced)
        {
            var applyMethod = GenerateApplyMethod(names);

            var doTransitionMethod = GenerateDoTransitionMethod(names);

            var classDeclaration = names.TryGetExtensionClass(documentRoot)
                                   .Match(ext => ext, () =>
            {
                var extensionClass = SyntaxFactory.ClassDeclaration(names.ExtensionClassName)
                                     .Public()
                                     .Static();
                documentRoot = documentRoot.AddMemberToNamespace(extensionClass);
                return(extensionClass);
            });

            classDeclaration = classDeclaration.AddOrUpdateMethod(m => m.Identifier.ToString() == StateMachineModel.ApplyMethodName && m.ParameterList.Parameters.Count == 2, applyMethod);
            classDeclaration = classDeclaration.AddOrUpdateMethod(m => m.Identifier.ToString() == StateMachineModel.DoTransitionMethodName && m.ParameterList.Parameters.Count == 2, doTransitionMethod);

            if (!funicularGeneratorsReferenced)
            {
                classDeclaration = classDeclaration
                                   .AddMatchMethods(
                    QualifiedTypeName.NoParents(names.BaseInterfaceName),
                    names.BaseName.ToParameterName(),
                    $"{StateMachineModel.StatePropertyName}.{StateMachineModel.EnumPropertyName}",
                    names.VertexClasses.Select(v => new MatchMethods.DerivedType(v.ClassName, v.StateName.ToParameterName(),
                                                                                 $"{names.OuterStateClassName}.{StateMachineModel.NestedEnumTypeName}.{v.StateName}"))
                    .ToImmutableList())
                                   .AddMatchMethods(
                    QualifiedTypeName.NoParents(names.ParameterInterfaceName),
                    "parameter",
                    $"{StateMachineModel.TriggerPropertyName}.{StateMachineModel.EnumPropertyName}",
                    names.VertexClasses.SelectMany(v => v.Transitions
                                                   .Select(t => new MatchMethods.DerivedType(t.FullParameterClassName,
                                                                                             t.MethodName.ToParameterName(),
                                                                                             $"{names.OuterTriggerClassName}.{StateMachineModel.NestedEnumTypeName}.{t.MethodName}")))
                    .Distinct().ToImmutableList()
                    );
            }

            return(documentRoot.ReplaceNode(names.TryGetExtensionClass(documentRoot).GetValueOrThrow(), classDeclaration));
        }
Exemplo n.º 9
0
        static SyntaxNode AddOrUpdateTransitionResultClass(SyntaxNode documentRoot, StateMachineModel names)
        {
            documentRoot = documentRoot.AddOrUpdateClass(names.TransitionResultClassName, c => c.Public().Abstract().AddMembers(), c => c);

            var baseList = SyntaxFactory.SimpleBaseType(SyntaxFactory.ParseTypeName(names.TransitionResultClassName));

            documentRoot = documentRoot.AddOrUpdateClass(names.TransitionResultTransitionClassName, c => c.Public().AddBaseListTypes(baseList), c => c
                                                         .AddPropertyIfNotExists(names.BaseInterfaceName, "Source", p => p.WithGetter())
                                                         .AddPropertyIfNotExists(names.BaseInterfaceName, "Destination", p => p.WithGetter())
                                                         .AddPropertyIfNotExists(names.ParameterInterfaceName, "Trigger", p => p.WithGetter())
                                                         .WithConstructorFromGetOnlyProperties()
                                                         );

            documentRoot = documentRoot.AddOrUpdateClass(names.TransitionResultInvalidTriggerClassName, c => c.Public().AddBaseListTypes(baseList), c => c
                                                         .AddPropertyIfNotExists(names.BaseInterfaceName, "Source", p => p.WithGetter())
                                                         .AddPropertyIfNotExists(names.ParameterInterfaceName, "Trigger", p => p.WithGetter())
                                                         .WithConstructorFromGetOnlyProperties()
                                                         );

            return(documentRoot);
        }
Exemplo n.º 10
0
 public GenerateStateClassesRewriter(StateMachineModel names) => m_Names = names;
Exemplo n.º 11
0
        static MethodDeclarationSyntax GenerateApplyMethod(string methodName, StateMachineModel names, TypeSyntax returnType,
                                                           Func <StateMachineModel.VertexClass, StateMachineModel.TransitionMethod, string, string, StatementSyntax> generateSwitchStatement, Func <StateMachineModel.VertexClass, string, string, StatementSyntax> generateDefaultStatement)
        {
            var baseTypeParameterName  = names.BaseName.ToParameterName();
            var parameterParameterName = "parameter";
            var baseType = SyntaxFactory.ParseTypeName(names.BaseInterfaceName);

            var applyMethod = SyntaxFactory.MethodDeclaration(returnType, methodName)
                              .Public()
                              .Static()
                              .WithParameterList(SyntaxFactory.ParameterList()
                                                 .AddParameters(
                                                     SyntaxFactory.Parameter(SyntaxFactory.ParseToken(baseTypeParameterName))
                                                     .WithModifiers(SyntaxTokenList.Create(SyntaxFactory.Token(SyntaxKind.ThisKeyword)))
                                                     .WithType(baseType),
                                                     SyntaxFactory.Parameter(SyntaxFactory.ParseToken(parameterParameterName))
                                                     .WithType(SyntaxFactory.ParseTypeName(names.ParameterInterfaceName))
                                                     )
                                                 )
                              .WithBody(SyntaxFactory.Block()
                                        .AddStatements(
                                            SyntaxFactory.SwitchStatement(SyntaxFactory.ParseExpression(
                                                                              $"{baseTypeParameterName}.{StateMachineModel.StatePropertyName}.{StateMachineModel.EnumPropertyName}"))
                                            .AddSections(names.VertexClasses.Select(vertex =>
                                                                                    SyntaxFactory.SwitchSection()
                                                                                    .AddLabels(SyntaxFactory.CaseSwitchLabel(SyntaxFactory.ParseExpression(
                                                                                                                                 $"{names.OuterStateClassName}.{StateMachineModel.NestedEnumTypeName}.{vertex.StateName}")))
                                                                                    .AddStatements(SyntaxFactory.Block(
                                                                                                       SyntaxFactory
                                                                                                       .SwitchStatement(SyntaxFactory.ParseExpression(
                                                                                                                            $"{parameterParameterName}.{StateMachineModel.TriggerPropertyName}.{StateMachineModel.EnumPropertyName}"))
                                                                                                       .AddSections(vertex.Transitions.Select(transition =>
                                                                                                                                              SyntaxFactory.SwitchSection()
                                                                                                                                              .AddLabels(SyntaxFactory.CaseSwitchLabel(
                                                                                                                                                             SyntaxFactory.ParseExpression(
                                                                                                                                                                 $"{names.OuterTriggerClassName}.{StateMachineModel.NestedEnumTypeName}.{transition.MethodName}")))
                                                                                                                                              .AddStatements(generateSwitchStatement(vertex, transition,
                                                                                                                                                                                     baseTypeParameterName, parameterParameterName))
                                                                                                                                              )
                                                                                                                    .Concat(new[]
            {
                SyntaxFactory.SwitchSection()
                .AddLabels(SyntaxFactory.DefaultSwitchLabel())
                .AddStatements(generateDefaultStatement(vertex,
                                                        baseTypeParameterName, parameterParameterName))
            })
                                                                                                                    .ToArray()
                                                                                                                    )
                                                                                                       ))
                                                                                    )
                                                         .Concat(new[]
            {
                SyntaxFactory.SwitchSection()
                .AddLabels(SyntaxFactory.DefaultSwitchLabel())
                .AddStatements(SyntaxFactory.ParseStatement(
                                   $"throw new ArgumentException($\"Unknown type implementing {names.BaseInterfaceName}: {{{baseTypeParameterName}.GetType().Name}}\");"))
            })
                                                         .ToArray()
                                                         )
                                            ));

            return(applyMethod);
        }