public static IEnumerable <SyntaxNode> BuildMethod(this RoslynTranslator roslynTranslator, IFunctionModel stack, IPortModel portModel)
        {
            roslynTranslator.ClearBuiltStacks();
            var generatedName    = roslynTranslator.MakeUniqueName(stack.CodeTitle);
            var methodSyntaxNode = RoslynBuilder.DeclareMethod(
                generatedName, AccessibilityFlags.Public, stack.ReturnType.Resolve(roslynTranslator.Stencil));
            var localDeclarationNodes = BuildLocalDeclarations(roslynTranslator, stack);
            var argumentNodes         = BuildArguments(roslynTranslator.Stencil, stack);

            methodSyntaxNode = methodSyntaxNode.WithParameterList(SyntaxFactory.ParameterList(
                                                                      SyntaxFactory.SeparatedList(argumentNodes.ToArray())));
            methodSyntaxNode = methodSyntaxNode.WithBody(SyntaxFactory.Block(localDeclarationNodes.ToArray()));

            if (stack.EnableProfiling)
            {
                throw new NotImplementedException("BuildMethod Profiling not implemented");
//                methodSyntaxNode = methodSyntaxNode.WithAdditionalAnnotations(InstrumentForProfiling.profilingAnnotation);
            }

            BlockSyntax stackBlock = SyntaxFactory.Block();

            roslynTranslator.BuildStack(stack, ref stackBlock);
            foreach (var statement in stackBlock.Statements)
            {
                methodSyntaxNode = methodSyntaxNode.AddBodyStatements(statement);
            }

            yield return(methodSyntaxNode);
        }
        public static IEnumerable <SyntaxNode> BuildIfCondition(this RoslynTranslator translator, IfConditionNodeModel statement, IPortModel portModel)
        {
            // this enables more elegant code generation with no duplication
            // if() { then(); } else { else(); }
            // codeAfterIf();
            // instead of duplicating the code after the if in each branch
            // find first stack reachable from both then/else stacks
            var firstThenStack = RoslynTranslator.GetConnectedStack(statement, 0);
            var firstElseStack = RoslynTranslator.GetConnectedStack(statement, 1);
            var endStack       = RoslynTranslator.FindCommonDescendant(statement.ParentStackModel, firstThenStack, firstElseStack);

            if (endStack != null)
            {
                // building the branches will stop at the common descendant
                translator.EndStack = endStack;
                // Debug.Log($"If in stack {statement.parentStackModel} Common descendant: {endStack}");
            }

            // ie. follow outputs, find all stacks with multiple inputs, compare them until finding the common one if it exists
            // BuildStack checks the m_EndStack field, returning when recursing on it
            // the parent buildStack call will then continue on this end stack


            var origBuiltStacks = translator.BuiltStacks;

            translator.BuiltStacks = new HashSet <IStackModel>(origBuiltStacks);
            HashSet <IStackModel> partialStacks = new HashSet <IStackModel>();

            StatementSyntax syntax = null;

            // construct multiple if else if else ... from right to left, starting with the last else
            foreach (var conditionWithAction in statement.ConditionsWithActionsPorts.Reverse())
            {
                var         stack = RoslynTranslator.GetConnectedStack(conditionWithAction.Action);
                BlockSyntax block = SyntaxFactory.Block();
                if (endStack == null || endStack != stack) // stop before the end stack
                {
                    translator.BuildStack(stack, ref block, StackExitStrategy.Inherit);
                }
                if (conditionWithAction.Condition == null) // last else
                {
                    syntax = block;
                }
                else // if = if() { current statement } else { prev statement that might be an if }
                {
                    var condition = (ExpressionSyntax)translator.BuildPort(conditionWithAction.Condition).SingleOrDefault();
                    syntax = SyntaxFactory.IfStatement(condition, block)
                             .WithElse(SyntaxFactory.ElseClause(syntax));
                }

                partialStacks.UnionWith(translator.BuiltStacks);
                translator.BuiltStacks = new HashSet <IStackModel>(origBuiltStacks);
            }

            translator.BuiltStacks = partialStacks;

            yield return(syntax);
        }
        public static IEnumerable <SyntaxNode> BuildMethod(this RoslynTranslator roslynTranslator, KeyDownEventModel stack, IPortModel portModel)
        {
            BlockSyntax block = SyntaxFactory.Block();

            roslynTranslator.BuildStack(stack, ref block);

            string methodName;

            switch (stack.mode)
            {
            case KeyDownEventModel.EventMode.Pressed:
                methodName = nameof(Input.GetKeyDown);
                break;

            case KeyDownEventModel.EventMode.Released:
                methodName = nameof(Input.GetKeyUp);
                break;

            default:
                methodName = nameof(Input.GetKey);
                break;
            }

            var conditionExpression = (ExpressionSyntax)roslynTranslator.BuildPort(stack.KeyPort).Single();

            IfStatementSyntax keydownCheck = (SyntaxFactory.IfStatement(
                                                  SyntaxFactory.InvocationExpression(
                                                      SyntaxFactory.MemberAccessExpression(
                                                          SyntaxKind.SimpleMemberAccessExpression,
                                                          SyntaxFactory.IdentifierName(nameof(Input)),
                                                          SyntaxFactory.IdentifierName(methodName)))
                                                  .WithArgumentList(
                                                      SyntaxFactory.ArgumentList(
                                                          SyntaxFactory.SingletonSeparatedList(
                                                              SyntaxFactory.Argument(
                                                                  conditionExpression)))),
                                                  block)
                                              .NormalizeWhitespace());

            roslynTranslator.AddEventRegistration(keydownCheck);
            yield break;
        }
        public static IEnumerable <SyntaxNode> BuildWhile(this RoslynTranslator translator, WhileHeaderModel whileHeaderModelStatement, IPortModel portModel)
        {
            if (whileHeaderModelStatement.IndexVariableDeclarationModel != null)
            {
                yield return(whileHeaderModelStatement.IndexVariableDeclarationModel.DeclareLoopIndexVariable());
            }

            var whileBlock = SyntaxFactory.Block();

            foreach (var localDeclaration in BuildLocalDeclarations(translator, whileHeaderModelStatement))
            {
                whileBlock = whileBlock.AddStatements(localDeclaration);
            }

            translator.BuildStack(whileHeaderModelStatement, ref whileBlock, StackExitStrategy.Continue);

            IPortModel loopExecutionInputPortModel = whileHeaderModelStatement.InputPort;
            IPortModel insertLoopPortModel         = loopExecutionInputPortModel?.ConnectionPortModels?.FirstOrDefault();
            var        insertLoopNodeModel         = insertLoopPortModel?.NodeModel as IHasMainInputPort;
            IPortModel conditionInputPortModel     = insertLoopNodeModel?.InputPort;

            SeparatedSyntaxList <ExpressionSyntax> incrementExpressions = SyntaxFactory.SeparatedList <ExpressionSyntax>();

            if (whileHeaderModelStatement.IndexVariableDeclarationModel != null)
            {
                incrementExpressions =
                    SyntaxFactory.SingletonSeparatedList <ExpressionSyntax>(
                        SyntaxFactory.PostfixUnaryExpression(
                            SyntaxKind.PostIncrementExpression,
                            SyntaxFactory.IdentifierName(whileHeaderModelStatement.IndexVariableDeclarationModel.name)));
            }

            yield return(SyntaxFactory.ForStatement(null, SyntaxFactory.SeparatedList <ExpressionSyntax>(),
                                                    translator.BuildPort(conditionInputPortModel).SingleOrDefault() as ExpressionSyntax,
                                                    incrementExpressions,
                                                    whileBlock));
        }
        public static IEnumerable <SyntaxNode> BuildForEach(this RoslynTranslator translator, ForEachHeaderModel forEachHeaderModelStatement,
                                                            IPortModel portModel)
        {
            IPortModel loopExecutionInputPortModel = forEachHeaderModelStatement.InputPort;
            IPortModel insertLoopPortModel         = loopExecutionInputPortModel?.ConnectionPortModels?.FirstOrDefault();
            var        insertLoopNodeModel         = insertLoopPortModel?.NodeModel as IHasMainInputPort;
            IPortModel collectionInputPortModel    = insertLoopNodeModel?.InputPort;

            if (collectionInputPortModel == null || !collectionInputPortModel.Connected ||
                !collectionInputPortModel.DataType.IsVsArrayType(translator.Stencil))
            {
                yield break;
            }

            var        collectionName   = translator.MakeUniqueName("Collection");
            SyntaxNode collectionSyntax =
                translator.BuildPort(collectionInputPortModel).SingleOrDefault();

            yield return(RoslynBuilder.DeclareLoopCollectionVariable(collectionSyntax, collectionName));

            if (forEachHeaderModelStatement.IndexVariableDeclarationModel != null)
            {
                yield return(forEachHeaderModelStatement.IndexVariableDeclarationModel.DeclareLoopIndexVariable(-1));
            }

            if (forEachHeaderModelStatement.CountVariableDeclarationModel != null)
            {
                var collectionInput =
                    translator.BuildPort(collectionInputPortModel).SingleOrDefault() as ExpressionSyntax;
                yield return(forEachHeaderModelStatement.CountVariableDeclarationModel.DeclareLoopCountVariable(
                                 collectionInput,
                                 collectionName,
                                 translator));
            }

            var forEachBlock = SyntaxFactory.Block();

            foreach (var localDeclaration in BuildLocalDeclarations(translator, forEachHeaderModelStatement))
            {
                forEachBlock = forEachBlock.AddStatements(localDeclaration);
            }


            if (forEachHeaderModelStatement.IndexVariableDeclarationModel != null)
            {
                forEachBlock = forEachBlock.AddStatements(SyntaxFactory.ExpressionStatement(
                                                              SyntaxFactory.PostfixUnaryExpression(
                                                                  SyntaxKind.PostIncrementExpression,
                                                                  SyntaxFactory.IdentifierName(forEachHeaderModelStatement.IndexVariableDeclarationModel.name)))
                                                          );
            }

            translator.BuildStack(forEachHeaderModelStatement, ref forEachBlock, StackExitStrategy.Continue);

            var itemModel = forEachHeaderModelStatement.ItemVariableDeclarationModel;

            if (itemModel == null)
            {
                yield break;
            }

            yield return(SyntaxFactory.ForEachStatement(
                             SyntaxFactory.IdentifierName("var"),
                             SyntaxFactory.Identifier(itemModel.VariableName),
                             SyntaxFactory.IdentifierName(collectionName),
                             forEachBlock));
        }