Exemplo n.º 1
0
        public void GenerateCode(State rootState, TextWriter output, string namespaceName, UsingList usings, string[] genericArguments)
        {
            _syntaxTypes.Clear();

            var code = new CodeCompileUnit();
            var ns = new CodeNamespace(namespaceName);
            code.Namespaces.Add(ns);
            ns.Imports.Add(new CodeNamespaceImport("System"));

            foreach (var u in usings)
            {
                ns.Imports.Add(new CodeNamespaceImport(u.Namespace));
            }

            GenerateCode(t => ns.Types.Add(t), rootState, new HashSet<string>(), genericArguments);

            ns.Types.Add(new CodeTypeDeclaration(_syntaxEnd)
            {
                Attributes = MemberAttributes.Public,
                TypeAttributes = TypeAttributes.Interface | TypeAttributes.Public,
                IsPartial = true,
            });

            var codeProvider = new CSharpCodeProvider();
            codeProvider.GenerateCodeFromCompileUnit(code, output, new CodeGeneratorOptions
            {
                BracingStyle = "C",
                IndentString = "\t",
            });
        }
Exemplo n.º 2
0
        private State BuildGraph(string name, OperationList operations, ICollection<State> allStates)
        {
            var entryState = new State(name, true, Enumerable.Empty<Parameter>());
            allStates.Add(entryState);

            var previousStates = new List<State> { entryState };
            foreach (var operation in operations)
            {
                BuildGraph(previousStates, operation, allStates);
            }
            return entryState;
        }
Exemplo n.º 3
0
 private static void TraverseStateGraph(State currentState, HashSet<State> visitedStates)
 {
     if (visitedStates.Add(currentState))
     {
         foreach (var nextState in currentState.NextStates)
         {
             TraverseStateGraph(nextState, visitedStates);
         }
         if (currentState.InnerState != null)
         {
             TraverseStateGraph(currentState.InnerState, visitedStates);
         }
     }
 }
Exemplo n.º 4
0
        private void BuildGraph(IList<State> previousStates, Operation operation, ICollection<State> allStates)
        {
            var currentState = new State(operation.Name, false, operation.Parameters);
            allStates.Add(currentState);

            foreach (var previousState in previousStates)
            {
                previousState.NextStates.Add(currentState);
            }

            switch (operation.Multiplicity)
            {
                case Multiplicity.One:
                    previousStates.Clear();
                    previousStates.Add(currentState);
                    break;

                case Multiplicity.ZeroOrOne:
                    previousStates.Add(currentState);
                    currentState.IsOptional = true;
                    break;

                case Multiplicity.OneOrMany:
                    previousStates.Clear();
                    previousStates.Add(currentState);

                    currentState.NextStates.Add(currentState);
                    break;

                case Multiplicity.ZeroOrMany:
                    previousStates.Add(currentState);
                    currentState.IsOptional = true;

                    currentState.NextStates.Add(currentState);
                    break;
            }

            if (operation.Operations.Any())
            {
                currentState.InnerState = BuildGraph(operation.Name + "Inner", operation.Operations, allStates);
            }
        }
Exemplo n.º 5
0
        private void GenerateCode(Action<CodeTypeDeclaration> addType, State entryState, HashSet<string> usedNames, string[] genericArguments)
        {
            var stateType = AddGenericArguments(new CodeTypeDeclaration(GenerateName("{0}{1}Builder", entryState.Name, usedNames))
            {
                IsPartial = true,
            }, genericArguments);

            addType(stateType);

            var states = new HashSet<State>();
            FlattenStateTree(entryState, states);
            foreach (var state in states)
            {
                // Create syntax interface type
                var interfaceType = AddGenericArguments(new CodeTypeDeclaration(GenerateName("{0}{1}Syntax", state.Name, usedNames))
                {
                    Attributes = MemberAttributes.Public,
                    TypeAttributes = TypeAttributes.Interface | TypeAttributes.Public,
                    IsPartial = true,
                }, genericArguments);

                addType(interfaceType);

                stateType.BaseTypes.Add(AddGenericArguments(interfaceType.Name, genericArguments));

                var syntaxType = stateType;

                // Create data container
                if (!state.IsRoot)
                {
                    syntaxType = AddGenericArguments(new CodeTypeDeclaration(GenerateName("{0}{1}Data", state.Name, usedNames))
                    {
                        Attributes = MemberAttributes.Final | MemberAttributes.Public,
                        TypeAttributes = TypeAttributes.Sealed | TypeAttributes.Public,
                        IsPartial = true,
                    }, genericArguments);

                    addType(syntaxType);

                    foreach (var parameter in state.Parameters)
                    {
                        syntaxType.Members.Add(
                            new CodeMemberField(
                                parameter.Type,
                                parameter.Name
                            )
                            {
                                Attributes = MemberAttributes.Public
                            }
                        );
                    }

                    // Add field for each subsequent state
                    var allowMultiple = state.NextStates.Contains(state);
                    CodeMemberField nextStateField;
                    if (allowMultiple)
                    {
                        var ilistType = new CodeTypeReference("System.Collections.Generic.IList");
                        ilistType.TypeArguments.Add(AddGenericArguments(syntaxType.Name, genericArguments));

                        var listType = new CodeTypeReference("System.Collections.Generic.List");
                        listType.TypeArguments.Add(AddGenericArguments(syntaxType.Name, genericArguments));

                        nextStateField = new CodeMemberField(ilistType, state.Name)
                        {
                            Attributes = MemberAttributes.Public,
                            InitExpression = new CodeObjectCreateExpression(listType)
                        };
                    }
                    else
                    {
                        nextStateField = new CodeMemberField(
                            AddGenericArguments(syntaxType.Name, genericArguments),
                            state.Name
                        ) { Attributes = MemberAttributes.Public };
                    }

                    stateType.Members.Add(nextStateField);

                    if (state.InnerState != null)
                    {
                        StateData innerStateData;
                        if (!_syntaxTypes.TryGetValue(state.InnerState, out innerStateData))
                        {
                            GenerateCode(addType, state.InnerState, usedNames, genericArguments);
                            innerStateData = _syntaxTypes[state.InnerState];
                        }

                        syntaxType.Members.Add(new CodeMemberField(
                            AddGenericArguments(innerStateData.SyntaxType.Name, genericArguments),
                            _inner
                        ) { Attributes = MemberAttributes.Public });
                    }
                }

                _syntaxTypes.Add(state, new StateData { SyntaxType = syntaxType, InterfaceType = interfaceType });
            }

            foreach (var state in states)
            {
                var stateData = _syntaxTypes[state];

                foreach (var nextState in state.NextStates)
                {
                    var nextStateData = _syntaxTypes[nextState];

                    // Add state transition method to interface
                    var stateTransitionInterfaceMethod = new CodeMemberMethod
                    {
                        Name = nextState.Name,
                    };

                    stateData.InterfaceType.Members.Add(stateTransitionInterfaceMethod);
                    stateTransitionInterfaceMethod.ReturnType = AddGenericArguments(nextStateData.InterfaceType.Name, genericArguments);

                    // Add state transition method to type
                    var stateTransitionMethod = new CodeMemberMethod
                    {
                        Name = nextState.Name,
                        PrivateImplementationType = AddGenericArguments(stateData.InterfaceType.Name, genericArguments),
                    };

                    stateType.Members.Add(stateTransitionMethod);
                    stateTransitionMethod.ReturnType = AddGenericArguments(nextStateData.InterfaceType.Name, genericArguments);

                    var variable = new CodeVariableDeclarationStatement(
                        AddGenericArguments(nextStateData.SyntaxType.Name, genericArguments),
                        "_" + nextState.Name,
                        new CodeObjectCreateExpression(AddGenericArguments(nextStateData.SyntaxType.Name, genericArguments))
                    );
                    stateTransitionMethod.Statements.Add(variable);

                    foreach (var parameter in nextState.Parameters)
                    {
                        var methodParameter = new CodeParameterDeclarationExpression(
                            parameter.Type,
                            parameter.Name
                        );

                        stateTransitionMethod.Parameters.Add(methodParameter);
                        stateTransitionInterfaceMethod.Parameters.Add(methodParameter);

                        stateTransitionMethod.Statements.Add(
                            new CodeAssignStatement(
                                new CodeFieldReferenceExpression(
                                    new CodeVariableReferenceExpression(variable.Name),
                                    parameter.Name
                                ),
                                new CodeSnippetExpression(methodParameter.Name)
                            )
                        );
                    }

                    var allowMultiple = nextState.NextStates.Contains(nextState);
                    if (allowMultiple)
                    {
                        stateTransitionMethod.Statements.Add(
                            new CodeMethodInvokeExpression(
                                new CodeFieldReferenceExpression(
                                    new CodeThisReferenceExpression(),
                                    nextState.Name
                                ),
                                "Add",
                                new CodeSnippetExpression(variable.Name)
                            )
                        );
                    }
                    else
                    {
                        stateTransitionMethod.Statements.Add(
                            new CodeAssignStatement(
                                new CodeFieldReferenceExpression(
                                    new CodeThisReferenceExpression(),
                                    nextState.Name
                                ),
                                new CodeSnippetExpression(variable.Name)
                            )
                        );
                    }

                    // Add parameter for inner state
                    if (nextState.InnerState != null)
                    {
                        var innerStateData = _syntaxTypes[nextState.InnerState];

                        var methodParameterType = new CodeTypeReference("Func");
                        methodParameterType.TypeArguments.Add(AddGenericArguments(innerStateData.InterfaceType.Name, genericArguments));
                        methodParameterType.TypeArguments.Add(_syntaxEnd);

                        var methodParameter = new CodeParameterDeclarationExpression(methodParameterType, _inner);

                        if (nextState.InnerState.IsTerminal)
                        {
                            methodParameter.CustomAttributes.Add(new CodeAttributeDeclaration(
                                new CodeTypeReference(typeof(OptionalAttribute))
                            ));
                        }

                        stateTransitionMethod.Parameters.Add(methodParameter);
                        stateTransitionInterfaceMethod.Parameters.Add(methodParameter);

                        stateTransitionMethod.Statements.Add(
                            new CodeAssignStatement(
                                new CodeFieldReferenceExpression(
                                    new CodeSnippetExpression("_" + nextState.Name),
                                    _inner
                                ),
                                new CodeObjectCreateExpression(AddGenericArguments(innerStateData.SyntaxType.Name, genericArguments))
                            )
                        );

                        stateTransitionMethod.Statements.Add(
                            new CodeConditionStatement(
                                new CodeBinaryOperatorExpression(
                                    new CodeArgumentReferenceExpression(_inner),
                                    CodeBinaryOperatorType.IdentityInequality,
                                    new CodePrimitiveExpression(null)
                                ),
                                new[]
                                {
                                    new CodeExpressionStatement(
                                        new CodeDelegateInvokeExpression(
                                            new CodeSnippetExpression(methodParameter.Name),
                                            new CodeFieldReferenceExpression(
                                                new CodeSnippetExpression("_" + nextState.Name),
                                                _inner
                                            )
                                        )
                                    )
                                },
                                nextState.InnerState.IsTerminal
                                    ? new CodeStatement[0]
                                    : new[]
                                    {
                                        new CodeThrowExceptionStatement(
                                            new CodeObjectCreateExpression(
                                                typeof(ArgumentNullException),
                                                new CodePrimitiveExpression(_inner)
                                            )
                                        )
                                    }
                            )
                        );
                    }

                    stateTransitionMethod.Statements.Add(
                        new CodeMethodReturnStatement(
                            new CodeThisReferenceExpression()
                        )
                    );
                }

                if (state.IsTerminal)
                {
                    stateData.InterfaceType.BaseTypes.Add(_syntaxEnd);
                }
            }
        }
Exemplo n.º 6
0
 private void FlattenStateTree(State entryState, HashSet<State> visitedStates)
 {
     if (visitedStates.Add(entryState))
     {
         foreach (var state in entryState.NextStates)
         {
             FlattenStateTree(state, visitedStates);
         }
     }
 }