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> 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));
            }
        }
Example #3
0
        IEnumerable <MemberDeclarationSyntax> BuildComponentMembers(RoslynTranslator translator)
        {
            var states     = new List <SwitchSectionSyntax>();
            var variables  = new Dictionary <string, FieldDeclarationSyntax>();
            var stateIndex = 0;

            // Add members (MoveNext + variables) from coroutine nodes in stack
            var stack = Parent.IterationContext.Query;

            BuildStack(translator, stack, ref variables, ref states, ref stateIndex);

            // Fields
            var members = new List <MemberDeclarationSyntax>
            {
                RoslynBuilder.DeclareField(
                    typeof(int),
                    RoslynEcsBuilder.CoroutineStateVariableName,
                    AccessibilityFlags.Private)
            };

            members.AddRange(variables.Values);

            // Parameters + Arguments
            foreach (var component in m_AccessedComponents)
            {
                var componentName = GetComponentVariableName(IterationContext.Query, component);
                var componentType = component.Resolve(IterationContext.Stencil);

                m_Parameters.Add(
                    Argument(IdentifierName(componentName))
                    .WithRefOrOutKeyword(Token(SyntaxKind.RefKeyword)),
                    Parameter(Identifier(componentName))
                    .WithModifiers(TokenList(Token(SyntaxKind.RefKeyword)))
                    .WithType(TypeSystem.BuildTypeSyntax(componentType)));
            }

            foreach (var localVariable in IterationContext.Query.FunctionVariableModels)
            {
                m_Parameters.Add(
                    Argument(IdentifierName(localVariable.Name)),
                    Parameter(Identifier(localVariable.Name))
                    .WithType(TypeSystem.BuildTypeSyntax(localVariable.DataType.Resolve(IterationContext.Stencil))));
            }

            // Create MoveNext method
            members.Add(
                RoslynBuilder.DeclareMethod(k_MoveNext, AccessibilityFlags.Public, typeof(bool))
                .WithParameterList(
                    ParameterList(SeparatedList(m_Parameters.Values)))
                .WithBody(
                    Block(
                        SwitchStatement(IdentifierName(RoslynEcsBuilder.CoroutineStateVariableName))
                        .WithOpenParenToken(Token(SyntaxKind.OpenParenToken))
                        .WithCloseParenToken(Token(SyntaxKind.CloseParenToken))
                        .WithSections(List(states)),
                        ReturnStatement(
                            LiteralExpression(SyntaxKind.FalseLiteralExpression)))));

            return(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> 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> 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 IEnumerable <SyntaxNode> BuildFunctionCall(this RoslynTranslator translator, FunctionCallNodeModel call, IPortModel portModel)
        {
            if (call.MethodInfo == null)
            {
                yield break;
            }

            var instance = BuildArgumentList(translator, call, out var argumentList);

            var typeArgumentList = new List <TypeSyntax>();

            if (call.MethodInfo.IsGenericMethod)
            {
                foreach (var typeArgument in call.TypeArguments)
                {
                    typeArgumentList.Add(TypeSystem.BuildTypeSyntax(typeArgument.Resolve(translator.Stencil)));
                }
            }

            TypeArgumentListSyntax typeArgList = null;

            if (typeArgumentList.Any())
            {
                typeArgList = SyntaxFactory.TypeArgumentList(SyntaxFactory.SingletonSeparatedList(typeArgumentList.First()));
            }

            SyntaxNode method = RoslynBuilder.MethodInvocation(call.Title, call.MethodInfo, instance, argumentList, typeArgList);

            yield return(method);
        }
        public static IEnumerable <SyntaxNode> BuildInlineExpression(this RoslynTranslator translator, InlineExpressionNodeModel v, IPortModel portModel)
        {
            var expressionCode        = "var ___exp = (" + v.Expression + ")";
            var syntaxTree            = CSharpSyntaxTree.ParseText(expressionCode);
            var buildInlineExpression = syntaxTree.GetRoot().DescendantNodesAndSelf().OfType <ParenthesizedExpressionSyntax>().FirstOrDefault();

            yield return(buildInlineExpression);
        }
        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> 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 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 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> 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> 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> 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();
            }
        }
        public static IEnumerable <SyntaxNode> BuildFunctionRefCall(this RoslynTranslator translator, FunctionRefCallNodeModel call, IPortModel portModel)
        {
            if (call.Function.Destroyed)
            {
                yield break;
            }
            ExpressionSyntax instance = BuildArgumentList(translator, call, out var argumentList);

            if (!call.Function.IsInstanceMethod)
            {
                instance = SyntaxFactory.IdentifierName(((VSGraphModel)call.Function.GraphModel).TypeName);
            }
            InvocationExpressionSyntax invocationExpressionSyntax = null;

#if UNITY_EDITOR
            var instancePort = call.InstancePort;
            if (instancePort != null && instancePort.DataType.GraphModelReference != null)
            {
                var genericTypeName = call.InstancePort.DataType.Name(translator.Stencil);
                invocationExpressionSyntax = FunctionInvokeExpression(genericTypeName, call.Function.CodeTitle, instance, argumentList);
            }
#endif
            // not a VisualBehaviour reference method call
            if (invocationExpressionSyntax == null)
            {
                invocationExpressionSyntax = instance == null ||
                                             (instance is LiteralExpressionSyntax &&
                                              (instance).IsKind(SyntaxKind.NullLiteralExpression))
                    ? SyntaxFactory.InvocationExpression(SyntaxFactory.IdentifierName(call.Function.CodeTitle))
                    : SyntaxFactory.InvocationExpression(
                    SyntaxFactory.MemberAccessExpression(
                        SyntaxKind.SimpleMemberAccessExpression,
                        instance,
                        SyntaxFactory.IdentifierName(call.Function.CodeTitle)))
                ;

                invocationExpressionSyntax = invocationExpressionSyntax.WithArgumentList(
                    SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList(argumentList)));
            }

            if (portModel == null)
            {
                yield return(SyntaxFactory.ExpressionStatement(
                                 invocationExpressionSyntax)
                             .NormalizeWhitespace());
            }
            else
            {
                yield return(invocationExpressionSyntax.NormalizeWhitespace());
            }
        }
        public static List <StatementSyntax> BuildLocalDeclarations(RoslynTranslator roslynTranslator, IFunctionModel stack)
        {
            var localDeclarationNodes = new List <StatementSyntax>();

            if (stack.VariableDeclarations == null)
            {
                return(localDeclarationNodes);
            }

            localDeclarationNodes.AddRange(stack.VariableDeclarations
                                           .Where(localDecl => localDecl.VariableType == VariableType.FunctionVariable)
                                           .Select(localDecl => localDecl.DeclareLocalVariable(roslynTranslator)));

            return(localDeclarationNodes);
        }
Example #18
0
        public static IEnumerable <SyntaxNode> BuildIfCondition(this RoslynEcsTranslator translator, IfConditionNodeModel statement, IPortModel portModel)
        {
            // TODO: de-duplicate code after if stacks
            var firstThenStack = RoslynTranslator.GetConnectedStack(statement, 0);
            var firstElseStack = RoslynTranslator.GetConnectedStack(statement, 1);

            // this enables more elegant code generation with no duplication
            // find first stack reachable from both then/else stacks
            var endStack = RoslynTranslator.FindCommonDescendant(firstThenStack, firstElseStack);

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

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

            var thenBlock = Block();

            if (endStack != firstThenStack)
            {
                translator.BuildStack(firstThenStack, ref thenBlock, StackExitStrategy.Inherit);
            }

            var elseBlock = Block();

            if (endStack != firstElseStack)
            {
                translator.BuildStack(firstElseStack, ref elseBlock, StackExitStrategy.Inherit);
            }

            var ifNode = RoslynBuilder.IfStatement(
                translator.BuildPort(statement.IfPort).SingleOrDefault(),
                thenBlock,
                elseBlock);

            yield return(ifNode);
        }
        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> BuildLoop(this RoslynTranslator translator, LoopNodeModel statement, IPortModel portModel)
        {
            IPortModel outputPortModel = statement.OutputPort;

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

            LoopStackModel loopStackModel =
                outputPortModel.ConnectionPortModels.FirstOrDefault()?.NodeModel as LoopStackModel;

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

            foreach (var statementSyntax in translator.BuildNode(loopStackModel))
            {
                yield return(statementSyntax);
            }
        }
        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> BuildFunctionRefCall(this RoslynTranslator translator, FunctionRefCallNodeModel call, IPortModel portModel)
        {
            if (call.Function.Destroyed)
            {
                yield break;
            }
            ExpressionSyntax instance = BuildArgumentList(translator, call, out var argumentList);

            if (!call.Function.IsInstanceMethod)
            {
                instance = SyntaxFactory.IdentifierName(((VSGraphModel)call.Function.GraphModel).TypeName);
            }

            var invocationExpressionSyntax = instance == null ||
                                             instance is LiteralExpressionSyntax &&
                                             instance.IsKind(SyntaxKind.NullLiteralExpression)
                ? SyntaxFactory.InvocationExpression(SyntaxFactory.IdentifierName(call.Function.CodeTitle))
                : SyntaxFactory.InvocationExpression(
                SyntaxFactory.MemberAccessExpression(
                    SyntaxKind.SimpleMemberAccessExpression,
                    instance,
                    SyntaxFactory.IdentifierName(call.Function.CodeTitle)))
            ;

            invocationExpressionSyntax = invocationExpressionSyntax.WithArgumentList(
                SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList(argumentList)));

            if (portModel == null)
            {
                yield return(SyntaxFactory.ExpressionStatement(
                                 invocationExpressionSyntax)
                             .NormalizeWhitespace());
            }
            else
            {
                yield return(invocationExpressionSyntax.NormalizeWhitespace());
            }
        }
        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));
        }
Example #24
0
        static void BuildStack(RoslynTranslator translator, IStackModel stack,
                               ref Dictionary <string, FieldDeclarationSyntax> variables, ref List <SwitchSectionSyntax> states,
                               ref int stateIndex)
        {
            translator.RegisterBuiltStack(stack);

            foreach (var node in stack.NodeModels)
            {
                switch (node)
                {
                case IfConditionNodeModel _:
                    translator.AddError(node, "Coroutine (e.g. Wait) and Condition nodes can't coexist within the same stack for now. This feature is coming in a further release");
                    continue;

                case ReturnNodeModel _:
                    translator.AddError(node, "Coroutine (e.g. Wait) and Return nodes can't coexist within the same stack for now. This feature is coming in a further release");
                    continue;
                }

                var blocks = translator.BuildNode(node);
                if (node is CoroutineNodeModel coroutineNode)
                {
                    foreach (var variable in coroutineNode.Fields)
                    {
                        if (variables.ContainsKey(variable.Key))
                        {
                            continue;
                        }

                        variables.Add(variable.Key, variable.Value);
                    }

                    foreach (var block in blocks)
                    {
                        states.Add(SwitchSection()
                                   .WithLabels(
                                       SingletonList <SwitchLabelSyntax>(
                                           CaseSwitchLabel(
                                               LiteralExpression(
                                                   SyntaxKind.NumericLiteralExpression,
                                                   Literal(stateIndex)))))
                                   .WithStatements(
                                       SingletonList(block as StatementSyntax)));

                        stateIndex++;
                    }
                }
                else
                {
                    var statements = new List <StatementSyntax>();
                    foreach (var block in blocks)
                    {
                        switch (block)
                        {
                        case StatementSyntax statementNode:
                            statements.Add(statementNode);
                            break;

                        case ExpressionSyntax expressionNode:
                            statements.Add(
                                ExpressionStatement(expressionNode)
                                .WithAdditionalAnnotations(
                                    new SyntaxAnnotation(Annotations.AnnotationKind,
                                                         node.NodeAssetReference.GetInstanceID().ToString())));
                            break;

                        default:
                            throw new InvalidOperationException("Expected a statement or expression " +
                                                                $"node, found a {node.GetType()} when building {block}");
                        }
                    }

                    states.Add(SwitchSection()
                               .WithLabels(
                                   SingletonList <SwitchLabelSyntax>(
                                       CaseSwitchLabel(
                                           LiteralExpression(
                                               SyntaxKind.NumericLiteralExpression,
                                               Literal(stateIndex)))))
                               .WithStatements(
                                   SingletonList((StatementSyntax)Block(statements)
                                                 .AddStatements(
                                                     RoslynEcsBuilder.BuildCoroutineNextState(),
                                                     ReturnStatement(
                                                         LiteralExpression(SyntaxKind.TrueLiteralExpression))))));

                    stateIndex++;
                }
            }

            foreach (var outputPort in stack.OutputPorts)
            {
                foreach (var connectedStack in outputPort.ConnectionPortModels)
                {
                    if (connectedStack.NodeModel is IStackModel nextStack)
                    {
                        BuildStack(translator, nextStack, ref variables, ref states, ref stateIndex);
                    }
                }
            }
        }
 public static IEnumerable <SyntaxNode> BuildStaticConstantNode(this RoslynTranslator translator, SystemConstantNodeModel model, IPortModel portModel)
 {
     yield return(SyntaxFactory.QualifiedName(
                      SyntaxFactory.IdentifierName(model.DeclaringType.Name(translator.Stencil)),
                      SyntaxFactory.IdentifierName(model.Identifier)));
 }
 public static IEnumerable <SyntaxNode> BuildThisNode(this RoslynTranslator translator, ThisNodeModel model, IPortModel portModel)
 {
     yield return(SyntaxFactory.ThisExpression());
 }
 public static IEnumerable <SyntaxNode> BuildUnaryOperator(this RoslynTranslator translator, UnaryOperatorNodeModel model, IPortModel portModel)
 {
     yield return(RoslynBuilder.UnaryOperator(model.kind, translator.BuildPort(model.InputPort).SingleOrDefault()));
 }
        public ClassDeclarationSyntax Build(RoslynTranslator translator, VSGraphModel graphModel)
        {
            var baseClass = m_NeedToCompleteDependenciesFirst ? nameof(ComponentSystem) : nameof(JobComponentSystem);

            m_ClassDeclaration = m_ClassDeclaration.WithBaseList(
                BaseList(
                    SingletonSeparatedList <BaseTypeSyntax>(
                        SimpleBaseType(
                            IdentifierName(baseClass)))));

            foreach (var queryTracking in m_QueryHasStateTracking)
            {
                var trackingMembers = new List <MemberDeclarationSyntax>();
                if (queryTracking.Value.Tracking)
                {
                    trackingMembers.Add(
                        FieldDeclaration(
                            VariableDeclaration(
                                PredefinedType(
                                    Token(SyntaxKind.BoolKeyword)))
                            .WithVariables(
                                SingletonSeparatedList(
                                    VariableDeclarator(
                                        Identifier("Processed")))))
                        .WithModifiers(
                            TokenList(
                                Token(SyntaxKind.InternalKeyword))));
                }

                DeclareComponent <ISystemStateComponentData>(queryTracking.Value.ComponentName, trackingMembers);
            }

            foreach (var eventSystem in m_EventSystems)
            {
                //  ClearEvents<TestEvent2>.Initialize(World);
                InitializationStatements.Add(ExpressionStatement(InvocationExpression(
                                                                     MemberAccessExpression(
                                                                         SyntaxKind.SimpleMemberAccessExpression,
                                                                         GenericName(
                                                                             Identifier("EventSystem"))
                                                                         .WithTypeArgumentList(
                                                                             TypeArgumentList(
                                                                                 SingletonSeparatedList <TypeSyntax>(
                                                                                     IdentifierName(eventSystem.FullName)))),
                                                                         IdentifierName("Initialize")))
                                                                 .WithArgumentList(
                                                                     ArgumentList(
                                                                         SingletonSeparatedList(
                                                                             Argument(
                                                                                 IdentifierName("World")))))));
            }

            if ((TranslationOptions & RoslynEcsTranslator.TranslationOptions.Tracing) != 0)
            {
                DeclareAndInitField(typeof(TracingRecorderSystem), nameof(TracingRecorderSystem), initValue: InvocationExpression(
                                        MemberAccessExpression(
                                            SyntaxKind.SimpleMemberAccessExpression,
                                            IdentifierName("World"),
                                            GenericName(
                                                Identifier(nameof(World.GetExistingSystem)))
                                            .WithTypeArgumentList(
                                                TypeArgumentList(
                                                    SingletonSeparatedList <TypeSyntax>(
                                                        IdentifierName(nameof(TracingRecorderSystem))))))));
            }
            HashSet <string> declaredQueries = new HashSet <string>();

            foreach (var group in m_WrittenComponentsPerGroup)
            {
                declaredQueries.Add(group.Key.Query.ComponentQueryDeclarationModel.GetId());
                DeclareEntityQueries(group.Value);
            }

            // declare unused queries in case there's a Count Entities In Query node somewhere
            foreach (var graphVariable in graphModel.GraphVariableModels.OfType <ComponentQueryDeclarationModel>().Where(q => !declaredQueries.Contains(q.GetId())))
            {
                var args = graphVariable.Components.Select(c => SyntaxFactory.Argument(
                                                               InvocationExpression(
                                                                   MemberAccessExpression(
                                                                       SyntaxKind.SimpleMemberAccessExpression,
                                                                       IdentifierName("ComponentType"),
                                                                       GenericName(
                                                                           Identifier("ReadOnly"))
                                                                       .WithTypeArgumentList(
                                                                           TypeArgumentList(
                                                                               SingletonSeparatedList <TypeSyntax>(
                                                                                   IdentifierName(c.Component.TypeHandle.Resolve(graphModel.Stencil)
                                                                                                  .FullName))))))
                                                               ));
                var initValue = MakeInitQueryExpression(args);

                DeclareAndInitField(typeof(EntityQuery), graphVariable.VariableName, initValue: initValue);
            }


            var singletonMembers = new List <FieldDeclarationSyntax>();
            var initArguments    = new List <AssignmentExpressionSyntax>();

            foreach (var graphVariable in graphModel.GraphVariableModels
                     .Where(g => g.VariableType == VariableType.GraphVariable))
            {
                singletonMembers.Add(graphVariable.DeclareField(translator, false)
                                     .WithAdditionalAnnotations(new SyntaxAnnotation(Annotations.VariableAnnotationKind)));
                initArguments.Add(RoslynBuilder.Assignment(
                                      IdentifierName(graphVariable.VariableName),
                                      translator.Constant(graphVariable.InitializationModel.ObjectValue, m_Stencil)));
            }

            if (singletonMembers.Any())
            {
                DeclareComponent <IComponentData>(SingletonComponentTypeName, singletonMembers);
                InitializationStatements.Add(ExpressionStatement(
                                                 RoslynBuilder.MethodInvocation(
                                                     nameof(EntityManager.CreateEntity),
                                                     IdentifierName(nameof(EntityManager)),
                                                     new[]
                {
                    Argument(TypeOfExpression(IdentifierName(SingletonComponentTypeName)))
                },
                                                     Enumerable.Empty <TypeSyntax>())));
                InitializationStatements.Add(
                    ExpressionStatement(
                        RoslynBuilder.MethodInvocation(
                            SafeGuardNamingSystem.SetSingletonName,
                            null,
                            new[]
                {
                    Argument(RoslynBuilder.DeclareNewObject(
                                 IdentifierName(SingletonComponentTypeName),
                                 Enumerable.Empty <ArgumentSyntax>(),
                                 initArguments))
                },
                            Enumerable.Empty <TypeSyntax>())));
            }

            // TODO : Remove this once there is real Systems' dependency tool
            var attributes = new List <AttributeListSyntax>();

            foreach (var assetModel in m_Stencil.UpdateAfter.Where(a => a.GraphModel.Stencil is EcsStencil))
            {
                RegisterAttributes <UpdateAfterAttribute>(attributes, assetModel.Name);
            }

            foreach (var assetModel in m_Stencil.UpdateBefore.Where(a => a.GraphModel.Stencil is EcsStencil))
            {
                RegisterAttributes <UpdateBeforeAttribute>(attributes, assetModel.Name);
            }

            m_ClassDeclaration = m_ClassDeclaration
                                 .AddAttributeLists(attributes.ToArray())
                                 .AddMembers(m_ClassMembers.OrderBy(x => x is FieldDeclarationSyntax ? 0 : 1).ToArray());

            if (m_InitializationStatements != null)
            {
                var onCreateManagerOverride = RoslynBuilder.DeclareMethod(
                    SafeGuardNamingSystem.OnCreateManagerName,
                    AccessibilityFlags.Protected | AccessibilityFlags.Override,
                    typeof(void));
                m_ClassDeclaration = m_ClassDeclaration
                                     .AddMembers(
                    onCreateManagerOverride.WithBody(
                        Block(m_InitializationStatements)));
            }

            if (m_SingletonUpdateSyntax != null)
            {
                AddStatement(m_SingletonUpdateSyntax);
            }

            var onUpdateBlock = Block(m_UpdateStatements);

            return(m_ClassDeclaration.AddMembers(
                       RoslynEcsTranslator.MakeOnUpdateOverride(
                           onUpdateBlock,
                           m_NeedToCompleteDependenciesFirst,
                           m_CreatedManagers)));
        }
        void BuildIfConditionNode(IfConditionNodeModel node, RoslynEcsTranslator translator, int stateIndex)
        {
            translator.BuildNode(node);

            var firstThenStack = RoslynTranslator.GetConnectedStack(node, 0);
            var firstElseStack = RoslynTranslator.GetConnectedStack(node, 1);
            var ifState        = m_States[stateIndex];
            var ifIndex        = GetCurrentStateIndex();

            var endStackIndex = 0;

            if (translator.EndStack != null)
            {
                m_StackIndexes.TryGetValue(translator.EndStack, out endStackIndex);
            }

            // Reserve then/else/complete states first
            var       thenIndex = ifIndex;
            var       thenBlock = Block().AddStatements(ReturnStatement(LiteralExpression(SyntaxKind.FalseLiteralExpression)));
            StateData thenState = null;

            if (firstThenStack != null)
            {
                if (firstThenStack == translator.EndStack && endStackIndex != 0)
                {
                    thenBlock = Block().AddStatements(BuildGoToState(endStackIndex));
                }
                else
                {
                    thenIndex += 1;
                    thenState  = RequestNewState();
                    TryAddStackIndex(firstThenStack, thenIndex);
                    thenBlock = Block().AddStatements(BuildGoToState(thenIndex));
                }
            }

            var       elseIndex = thenIndex + 1;
            var       elseBlock = Block().AddStatements(ReturnStatement(LiteralExpression(SyntaxKind.FalseLiteralExpression)));
            StateData elseState = null;

            if (firstElseStack != null)
            {
                if (firstElseStack == translator.EndStack && endStackIndex != 0)
                {
                    elseBlock = Block().AddStatements(BuildGoToState(endStackIndex));
                }
                else
                {
                    elseState = RequestNewState();
                    TryAddStackIndex(firstElseStack, elseIndex);
                    elseBlock = Block().AddStatements(BuildGoToState(elseIndex));
                }
            }

            // Then Build stacks
            ifState.Statements.Add(RoslynBuilder.IfStatement(
                                       translator.BuildPort(node.IfPort).SingleOrDefault(),
                                       thenBlock,
                                       elseBlock)
                                   .WithAdditionalAnnotations(
                                       new SyntaxAnnotation(Annotations.VSNodeMetadata, node.Guid.ToString())));
            ifState.Statements.Add(ReturnStatement(LiteralExpression(SyntaxKind.TrueLiteralExpression)));
            ifState.SkipStateBuilding = true;

            var reserveEndStackState = translator.EndStack != null &&
                                       translator.EndStack != firstElseStack &&
                                       translator.EndStack != firstThenStack &&
                                       endStackIndex == 0;

            if (reserveEndStackState)
            {
                var endState = RequestNewState();
                endState.NextStateIndex = GetNextStateIndex(translator.EndStack);
                TryAddStackIndex(translator.EndStack, GetCurrentStateIndex());
            }

            var origBuiltStacks = translator.BuiltStacks;

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

            if (translator.EndStack != firstThenStack)
            {
                if (translator.EndStack != null && thenState != null)
                {
                    thenState.NextStateIndex = m_StackIndexes[translator.EndStack];
                }
                BuildStack(translator, firstThenStack, thenIndex, StackExitStrategy.Inherit);
            }

            var partialStacks = translator.BuiltStacks;

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

            if (translator.EndStack != firstElseStack)
            {
                if (translator.EndStack != null && elseState != null)
                {
                    elseState.NextStateIndex = m_StackIndexes[translator.EndStack];
                }
                BuildStack(translator, firstElseStack, elseIndex, StackExitStrategy.Inherit);
            }

            translator.BuiltStacks.UnionWith(partialStacks);
        }
        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));
        }