public static IEnumerable <SyntaxNode> BuildSetPropertyNode(this RoslynTranslator translator, SetPropertyGroupNodeModel model, IPortModel portModel)
        {
            SyntaxNode leftHand;

            IPortModel instancePort = model.InstancePort;

            if (!instancePort.Connected)
            {
                leftHand = SyntaxFactory.ThisExpression();
            }
            else
            {
                leftHand = translator.BuildPort(instancePort).SingleOrDefault();
            }

            foreach (var member in model.Members)
            {
                string     memberId  = member.GetId();
                IPortModel inputPort = model.InputsById[memberId];

                SyntaxNode rightHandExpression = translator.BuildPort(inputPort).SingleOrDefault();
                if (rightHandExpression == null)
                {
                    continue;
                }

                MemberAccessExpressionSyntax access = RoslynBuilder.MemberReference(leftHand, member.Path[0]);
                for (int i = 1; i < member.Path.Count; i++)
                {
                    access = RoslynBuilder.MemberReference(access, member.Path[i]);
                }

                yield return(SyntaxFactory.AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, access, rightHandExpression as ExpressionSyntax));
            }
        }
        public static IEnumerable <SyntaxNode> BuildSetVariable(this RoslynTranslator translator, SetVariableNodeModel statement, IPortModel portModel)
        {
            var decl  = translator.BuildPort(statement.InstancePort).SingleOrDefault();
            var value = translator.BuildPort(statement.ValuePort).SingleOrDefault();

            yield return(decl == null || value == null ? null : RoslynBuilder.Assignment(decl, value));
        }
        public static SyntaxNode SetProperty(RoslynTranslator translator, AssignmentKind kind,
                                             IPortModel instancePortModel, IPortModel valuePortModel, params string[] members)
        {
            ExpressionSyntax instance = instancePortModel.Connected
                ? translator.BuildPort(instancePortModel).FirstOrDefault() as ExpressionSyntax
                : SyntaxFactory.ThisExpression();
            ExpressionSyntax value = translator.BuildPort(valuePortModel).FirstOrDefault() as ExpressionSyntax;

            return(SetProperty(kind, instance, value, members));
        }
        public static IEnumerable <SyntaxNode> BuildMacroRefNode(this RoslynTranslator translator,
                                                                 MacroRefNodeModel model, IPortModel portModel)
        {
            if (model.Macro == null)
            {
                translator.AddError(
                    model,
                    $"The asset of macro node {model.Title} is missing.");
                return(Enumerable.Empty <SyntaxNode>());
            }

            var variableDeclarations = portModel.Direction == Direction.Input
                ? model.DefinedInputVariables
                : model.DefinedOutputVariables;
            var declaration = variableDeclarations.Single(v => v.VariableName == portModel.UniqueId);

            translator.InMacro.Push(model);
            var variableNodeModel = ((VSGraphModel)declaration.GraphModel)
                                    .FindUsages((VariableDeclarationModel)declaration)
                                    .Single();
            var returnValue = translator.BuildPort(variableNodeModel.OutputPort);

            translator.InMacro.Pop();
            return(returnValue);
        }
        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 SyntaxNode GetProperty(RoslynTranslator translator, IPortModel instancePortModel,
                                             params string[] members)
        {
            ExpressionSyntax instance = instancePortModel.Connected
                ? translator.BuildPort(instancePortModel).FirstOrDefault() as ExpressionSyntax
                : SyntaxFactory.ThisExpression();

            return(GetProperty(instance, members));
        }
        public static IEnumerable <SyntaxNode> BuildUnaryOperator(this RoslynTranslator translator, UnaryOperatorNodeModel model, IPortModel portModel)
        {
            var semantic = model.Kind == UnaryOperatorKind.PostDecrement ||
                           model.Kind == UnaryOperatorKind.PostIncrement
                ? RoslynTranslator.PortSemantic.Write
                : RoslynTranslator.PortSemantic.Read;

            yield return(RoslynBuilder.UnaryOperator(model.Kind, translator.BuildPort(model.InputPort, semantic).SingleOrDefault()));
        }
 public static IEnumerable <SyntaxNode> BuildReturn(this RoslynTranslator translator, ReturnNodeModel returnModel, IPortModel portModel)
 {
     if (returnModel.InputPort == null)
     {
         yield return(SyntaxFactory.ReturnStatement());
     }
     else
     {
         yield return(SyntaxFactory.ReturnStatement(
                          translator.BuildPort(returnModel.InputPort).FirstOrDefault() as ExpressionSyntax));
     }
 }
 public static IEnumerable <SyntaxNode> BuildReturn(this RoslynTranslator translator, ReturnNodeModel returnModel, IPortModel portModel)
 {
     if (returnModel.ParentStackModel.OwningFunctionModel.ReturnType == typeof(void).GenerateTypeHandle(translator.Stencil))
     {
         yield return(SyntaxFactory.ReturnStatement());
     }
     else
     {
         yield return(SyntaxFactory.ReturnStatement(
                          translator.BuildPort(returnModel.InputPort).FirstOrDefault() as ExpressionSyntax));
     }
 }
        public static IEnumerable <SyntaxNode> BuildVariable(this RoslynTranslator translator, IVariableModel v, IPortModel portModel)
        {
            if (v is IConstantNodeModel constantNodeModel)
            {
                if (constantNodeModel.ObjectValue != null)
                {
                    if (constantNodeModel is IStringWrapperConstantModel)
                    {
                        yield return(translator.Constant(constantNodeModel.ObjectValue.ToString(), translator.Stencil));
                    }
                    else
                    {
                        yield return(translator.Constant(constantNodeModel.ObjectValue, translator.Stencil));
                    }
                }

                yield break;
            }

            if (translator.InMacro.Count > 0 && v.DeclarationModel.VariableType == VariableType.GraphVariable && v.DeclarationModel.Modifiers == ModifierFlags.ReadOnly)
            {
                MacroRefNodeModel oldValue = translator.InMacro.Pop();

                var syntaxNodes = translator.BuildPort(oldValue.InputsById[v.DeclarationModel.VariableName]);
                translator.InMacro.Push(oldValue);
                foreach (var syntaxNode in syntaxNodes)
                {
                    yield return(syntaxNode);
                }
                yield break;
            }

            switch (v.DeclarationModel.VariableType)
            {
            case VariableType.FunctionVariable:
            case VariableType.GraphVariable:
            case VariableType.ComponentQueryField:
                yield return(RoslynBuilder.LocalVariableReference(v.DeclarationModel.Name));

                break;

            case VariableType.FunctionParameter:
                yield return(RoslynBuilder.ArgumentReference(v.DeclarationModel.Name));

                break;

//                case VariableType.Literal:
//                case VariableType.InlineExpression:
            default:
                throw new ArgumentOutOfRangeException();
            }
        }
        static ExpressionSyntax BuildArgumentList(RoslynTranslator translator, IFunctionCallModel call, out List <ArgumentSyntax> argumentList)
        {
            ExpressionSyntax instance = null;

            if (call is IHasInstancePort modelWithInstancePort && modelWithInstancePort.InstancePort != null)
            {
                instance = (ExpressionSyntax)translator.BuildPort(modelWithInstancePort.InstancePort).SingleOrDefault();
            }

            argumentList = new List <ArgumentSyntax>();
            foreach (IPortModel port in call.GetParameterPorts())
            {
                var syntaxNode = translator.BuildPort(port).SingleOrDefault();
                if (syntaxNode != null)
                {
                    var argumentNode = syntaxNode as ArgumentSyntax ?? SyntaxFactory.Argument(syntaxNode as ExpressionSyntax);
                    argumentList.Add(argumentNode);
                }
            }

            return(instance);
        }
        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> BuildUnaryOperator(this RoslynTranslator translator, UnaryOperatorNodeModel model, IPortModel portModel)
 {
     yield return(RoslynBuilder.UnaryOperator(model.kind, translator.BuildPort(model.InputPort).SingleOrDefault()));
 }
        public static IEnumerable <SyntaxNode> BuildGetPropertyNode(this RoslynTranslator translator, GetPropertyGroupNodeModel model, IPortModel portModel)
        {
            var instancePort = model.InstancePort;
            var input        = !instancePort.Connected ? SyntaxFactory.ThisExpression() : translator.BuildPort(instancePort).SingleOrDefault();

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

            var member = model.Members.FirstOrDefault(m => m.GetId() == portModel.UniqueId);

            if (member.Path == null || member.Path.Count == 0)
            {
                yield break;
            }

            var access = RoslynBuilder.MemberReference(input, member.Path[0]);

            for (int i = 1; i < member.Path.Count; i++)
            {
                access = RoslynBuilder.MemberReference(access, member.Path[i]);
            }

            yield return(access);
        }
        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));
        }