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);
        }
示例#2
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);
        }
        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);
        }