/// <summary>
        /// Inserts code for bubbling yield assignments
        /// at the given position, returns position after inserted operations
        /// </summary>
        private SearchProgramOperation insertYieldAssignments(
            SearchProgramOperation insertionPoint,
            PatternGraph patternGraph,
            String nestedMatchObjectName,
            PatternGraph nestedPatternGraph)
        {
            foreach(PatternNode node in patternGraph.nodesPlusInlined)
            {
                if(!node.DefToBeYieldedTo)
                    continue;

                foreach(PatternNode nestedNode in nestedPatternGraph.nodesPlusInlined)
                {
                    if(nestedNode == node)
                    {
                        BubbleUpYieldAssignment bubble = new BubbleUpYieldAssignment(
                            EntityType.Node,
                            node.Name,
                            nestedMatchObjectName,
                            nestedNode.originalNode!=null && patternGraph.WasInlinedHere(nestedNode.originalSubpatternEmbedding) ? nestedNode.originalNode.UnprefixedName : nestedNode.UnprefixedName
                            );
                        insertionPoint = insertionPoint.Append(bubble);
                    }
                }
            }

            foreach(PatternEdge edge in patternGraph.edgesPlusInlined)
            {
                if(!edge.DefToBeYieldedTo)
                    continue;

                foreach(PatternEdge nestedEdge in nestedPatternGraph.edgesPlusInlined)
                {
                    if(nestedEdge == edge)
                    {
                        BubbleUpYieldAssignment bubble = new BubbleUpYieldAssignment(
                            EntityType.Edge,
                            edge.Name,
                            nestedMatchObjectName,
                            nestedEdge.originalElement!=null ? nestedEdge.originalEdge.UnprefixedName : nestedEdge.UnprefixedName
                            );
                        insertionPoint = insertionPoint.Append(bubble);
                    }
                }
            }
            
            foreach(PatternVariable var in patternGraph.variablesPlusInlined)
            {
                if(!var.DefToBeYieldedTo)
                    continue;

                foreach(PatternVariable nestedVar in nestedPatternGraph.variablesPlusInlined)
                {
                    if(nestedVar == var)
                    {
                        BubbleUpYieldAssignment bubble = new BubbleUpYieldAssignment(
                            EntityType.Variable,
                            var.Name,
                            nestedMatchObjectName,
                            nestedVar.originalVariable!=null ? nestedVar.originalVariable.UnprefixedName : nestedVar.UnprefixedName
                            );
                        insertionPoint = insertionPoint.Append(bubble);
                    }
                }
            }

            return insertionPoint;
        }
        /// <summary>
        /// Inserts code to yield, bubbling effects of nested yields upwards and computing local yields 
        /// at the given position, returns position after inserted operations
        /// </summary>
        private SearchProgramOperation insertYields(
            SearchProgramOperation insertionPoint,
            PatternGraph patternGraph,
            String matchObjectName,
            bool inlined)
        {
            // the match object is built now with our local elements
            // and the match objects of our children
            // now 1. copy all def entities we share with children to our local variables

            foreach(PatternGraphEmbedding patternEmbedding in patternGraph.embeddedGraphsPlusInlined)
            {
                // in the inlined pass only the elements which were inlined into this pattern, in the non-inlined pass the original elements
                bool wasInlined = patternEmbedding.originalEmbedding != null;
                if(inlined == wasInlined)
                {
                    // if the pattern embedding does not contain a def entity it can't yield to us
                    if(!((PatternGraph)patternEmbedding.EmbeddedGraph).isDefEntityExistingPlusInlined)
                        continue;
                    // skip inlined embeddings (will be handled in 3.)
                    if(patternEmbedding.inlined)
                        continue;

                    // in inlined pass bubble up from the components of the inlined patterns to the elements resulting from of the inlined pattern 
                    // (read from submatches to local variables, compute in local variables, writing will happen later from local variables to matches)
                    string inlinedMatchObjectName = null;
                    string patternEmbeddingName = patternEmbedding.Name;
                    if(patternEmbedding.originalEmbedding != null)
                    {
                        if(patternGraph.WasInlinedHere(patternEmbedding.originalSubpatternEmbedding))
                            inlinedMatchObjectName = "match_" + patternEmbedding.originalSubpatternEmbedding.Name;
                        patternEmbeddingName = patternEmbedding.originalEmbedding.name;
                    }

                    LGSPMatchingPattern matchingPattern = patternEmbedding.matchingPatternOfEmbeddedGraph;
                    String nestedMatchObjectName = (inlinedMatchObjectName ?? matchObjectName) + "._" + patternEmbeddingName;
                    Debug.Assert(matchingPattern.defNames.Length == patternEmbedding.yields.Length);
                    for(int i = 0; i < patternEmbedding.yields.Length; ++i)
                    {
                        BubbleUpYieldAssignment bubble = new BubbleUpYieldAssignment(
                            toBubbleUpYieldAssignmentType(matchingPattern.defs[i]),
                            patternEmbedding.yields[i],
                            nestedMatchObjectName,
                            matchingPattern.defNames[i]
                            );
                        insertionPoint = insertionPoint.Append(bubble);
                    }
                }
            }

            foreach(Iterated iterated in patternGraph.iteratedsPlusInlined)
            {
                // in the inlined pass only the elements which were inlined into this pattern, in the non-inlined pass the original elements
                bool wasInlined = iterated.originalIterated != null;
                if(inlined == wasInlined)
                {
                    // if the iterated does not contain a non local def entity it can't yield to us
                    if(!iterated.iteratedPattern.isNonLocalDefEntityExistingPlusInlined)
                        continue;

                    // in inlined pass bubble up from the components of the inlined patterns to the elements resulting from of the inlined pattern 
                    // (read from submatches to local variables, compute in local variables, writing will happen later from local variables to matches)
                    string inlinedMatchObjectName = null;
                    string iteratedName = iterated.iteratedPattern.Name;
                    if(iterated.originalIterated != null)
                    {
                        if(patternGraph.WasInlinedHere(iterated.originalSubpatternEmbedding))
                            inlinedMatchObjectName = "match_" + iterated.originalSubpatternEmbedding.Name;
                        iteratedName = iterated.originalIterated.iteratedPattern.name;
                    }

                    String nestedMatchObjectName = (inlinedMatchObjectName ?? matchObjectName) + "._" + iteratedName;
                    BubbleUpYieldIterated bubbleUpIterated = new BubbleUpYieldIterated(nestedMatchObjectName);
                    bubbleUpIterated.NestedOperationsList = new SearchProgramList(bubbleUpIterated);
                    SearchProgramOperation continuationPoint = insertionPoint.Append(bubbleUpIterated);
                    insertionPoint = bubbleUpIterated.NestedOperationsList;

                    insertYieldAssignments(insertionPoint,
                        patternGraph, nestedMatchObjectName + ".Root", iterated.iteratedPattern);

                    insertionPoint = continuationPoint;
                }
            }
            foreach(Alternative alternative in patternGraph.alternativesPlusInlined)
            {
                // in the inlined pass only the elements which were inlined into this pattern, in the non-inlined pass the original elements
                bool wasInlined = alternative.originalAlternative != null;
                if(inlined == wasInlined)
                {
                    bool first = true;
                    foreach(PatternGraph alternativeCase in alternative.alternativeCases)
                    {
                        // if the alternative case does not contain a non local def entity it can't yield to us
                        if(!alternativeCase.isNonLocalDefEntityExistingPlusInlined)
                            continue;

                        // in inlined pass bubble up from the components of the inlined patterns to the elements resulting from of the inlined pattern 
                        // (read from submatches to local variables, compute in local variables, writing will happen later from local variables to matches)
                        string inlinedMatchObjectName = matchObjectName;
                        string inlinedNestedMatchObjectName = "_" + alternative.name;
                        string inlinedPatternClassName = rulePatternClassName;
                        string patternElementType = patternGraph.pathPrefix + patternGraph.name + "_" + alternative.name + "_" + alternativeCase.name;
                        if(alternative.originalAlternative != null)
                        {
                            if(patternGraph.WasInlinedHere(alternative.originalSubpatternEmbedding))
                                inlinedMatchObjectName = "match_" + alternative.originalSubpatternEmbedding.name;
                            inlinedNestedMatchObjectName = "_" + alternative.originalAlternative.name;
                            inlinedPatternClassName = alternative.originalSubpatternEmbedding.matchingPatternOfEmbeddedGraph.GetType().Name;
                            patternElementType = alternative.originalAlternative.pathPrefix + alternative.originalAlternative.name + "_" + alternativeCase.originalPatternGraph.name;
                        }
                        
                        BubbleUpYieldAlternativeCase bubbleUpAlternativeCase =
                            new BubbleUpYieldAlternativeCase(
                                inlinedMatchObjectName,
                                inlinedNestedMatchObjectName,
                                inlinedPatternClassName + ".Match_" + patternElementType,
                                "altCaseMatch",
                                first);
                        bubbleUpAlternativeCase.NestedOperationsList = new SearchProgramList(bubbleUpAlternativeCase);
                        SearchProgramOperation continuationPoint = insertionPoint.Append(bubbleUpAlternativeCase);
                        insertionPoint = bubbleUpAlternativeCase.NestedOperationsList;
                        first = false;

                        insertYieldAssignments(insertionPoint,
                            patternGraph, "altCaseMatch", alternativeCase);

                        insertionPoint = continuationPoint;
                    }
                }
            }

            foreach(PatternGraph independent in patternGraph.independentPatternGraphsPlusInlined)
            {
                // in the inlined pass only the elements which were inlined into this pattern, in the non-inlined pass the original elements
                bool wasInlined = independent.originalPatternGraph != null;
                if(inlined == wasInlined)
                {
                    // if the independent does not contain a non local def entity it can't yield to us
                    if(!independent.isNonLocalDefEntityExistingPlusInlined)
                        continue;

                    // in inlined pass bubble up from the components of the inlined patterns to the elements resulting from of the inlined pattern 
                    // (read from submatches to local variables, compute in local variables, writing will happen later from local variables to matches)
                    string inlinedMatchObjectName = null;
                    if(independent.originalPatternGraph != null && patternGraph.WasInlinedHere(independent.originalSubpatternEmbedding))
                    {
                        inlinedMatchObjectName = "match_" + independent.originalSubpatternEmbedding.Name;
                    }

                    String nestedMatchObjectName = NamesOfEntities.MatchedIndependentVariable(independent.pathPrefix + independent.name); ;

                    insertionPoint = insertYieldAssignments(insertionPoint,
                        patternGraph, inlinedMatchObjectName ?? nestedMatchObjectName, independent);
                }
            }

            //////////////////////////////////////////////////////
            // then 2. compute all local yields
            PatternYielding[] patternYieldings;
            if(patternGraph.parallelizedSchedule != null) // in case of parallelization we've to use the parallelized yieldings
                patternYieldings = patternGraph.parallelizedYieldings;
            else
                patternYieldings = patternGraph.YieldingsPlusInlined;
            foreach(PatternYielding patternYielding in patternYieldings)
            {
                // in the inlined pass only the elements which were inlined into this pattern, in the non-inlined pass the original elements
                bool wasInlined = patternYielding.originalYielding != null;
                if(inlined == wasInlined)
                {
                    YieldingBlock yieldingBlock = new YieldingBlock(patternYielding.Name);
                    yieldingBlock.NestedOperationsList = new SearchProgramList(yieldingBlock);
                    SearchProgramOperation continuationPointOuter = insertionPoint.Append(yieldingBlock);
                    insertionPoint = yieldingBlock.NestedOperationsList;
                    
                    foreach(Yielding yielding in patternYielding.ElementaryYieldings)
                    {
                        // iterated potentially matching more than once can't be bubbled up normally,
                        // they need accumulation with a for loop into a variable of the nesting pattern, 
                        // that's done in/with the yield statements of the parent
                        if(yielding is IteratedAccumulationYield)
                        {
                            IteratedAccumulationYield accumulationYield = (IteratedAccumulationYield)yielding;
                            foreach(Iterated iterated in patternGraph.iteratedsPlusInlined)
                            {
                                // skip the iterateds we're not interested in
                                if(accumulationYield.Iterated != iterated.iteratedPattern.Name)
                                    continue;

                                // in inlined pass bubble up from the components of the inlined patterns to the elements resulting from of the inlined pattern 
                                // (read from submatches to local variables, compute in local variables, writing will happen later from local variables to matches)
                                string inlinedMatchObjectName = null;
                                if(iterated.originalIterated != null)
                                {
                                    inlinedMatchObjectName = "match_" + iterated.originalSubpatternEmbedding.Name;
                                }

                                String nestedMatchObjectName = (inlinedMatchObjectName ?? matchObjectName) + "._" + iterated.iteratedPattern.Name;
                                AccumulateUpYieldIterated accumulateUpIterated =
                                    new AccumulateUpYieldIterated(
                                        nestedMatchObjectName,
                                        rulePatternClassName + ".Match_" + patternGraph.pathPrefix + patternGraph.name + "_" + iterated.iteratedPattern.name,
                                        "iteratedMatch");
                                accumulateUpIterated.NestedOperationsList = new SearchProgramList(accumulateUpIterated);
                                SearchProgramOperation continuationPoint = insertionPoint.Append(accumulateUpIterated);
                                insertionPoint = accumulateUpIterated.NestedOperationsList;

                                accumulationYield.IteratedMatchVariable = "iteratedMatch._" + NamesOfEntities.Variable(accumulationYield.UnprefixedVariable);
                                accumulationYield.ReplaceVariableByIterationVariable(accumulationYield);

                                SourceBuilder yieldAssignmentSource = new SourceBuilder();
                                accumulationYield.Emit(yieldAssignmentSource);
                                LocalYielding yieldAssignment =
                                    new LocalYielding(yieldAssignmentSource.ToString());
                                insertionPoint = insertionPoint.Append(yieldAssignment);

                                insertionPoint = continuationPoint;
                            }
                        }
                        else
                        {
                            SourceBuilder yieldAssignmentSource = new SourceBuilder();
                            yielding.Emit(yieldAssignmentSource);
                            LocalYielding yieldAssignment =
                                new LocalYielding(yieldAssignmentSource.ToString());
                            insertionPoint = insertionPoint.Append(yieldAssignment);
                        }
                    }

                    insertionPoint = continuationPointOuter;
                }
            }

            //////////////////////////////////////////////////////
            // 3. at the end of the inlined pass:
            // assign the def parameters from a subpattern which was inlined to the arguments yielded to
            // we can't read from the match objects of the inlined subpatterns cause they are not written yet, but from the corresponding local variables
            if(inlined)
            {
                foreach(PatternGraphEmbedding patternEmbedding in patternGraph.embeddedGraphsPlusInlined)
                {
                    // only inlined embeddings
                    if(!patternEmbedding.inlined)
                        continue;

                    for(int i = 0; i < patternEmbedding.yields.Length; ++i)
                    {
                        String targetName = patternEmbedding.yields[i];
                        String sourceName = patternEmbedding.matchingPatternOfEmbeddedGraph.defNames[i];
                        IPatternElement elem = getInlinedElementByOriginalUnprefixedName(patternGraph, patternEmbedding, sourceName);
                        
                        // find the one which was originating from inlining patternEmbedding, because of same originator
                        bool isVariable = patternEmbedding.matchingPatternOfEmbeddedGraph.defs[i] is VarType;
                        YieldAssignment assignment = new YieldAssignment(
                            targetName,
                            isVariable,
                            patternEmbedding.matchingPatternOfEmbeddedGraph.defs[i] is VarType ? TypesHelper.TypeName(patternEmbedding.matchingPatternOfEmbeddedGraph.defs[i]) : patternEmbedding.matchingPatternOfEmbeddedGraph.defs[i].IsNodeType ? "GRGEN_LGSP.LGSPNode" : "GRGEN_LGSP.LGSPEdge",
                            isVariable ? (Expression)new VariableExpression(elem.Name) : (Expression)new GraphEntityExpression(elem.Name)
                        );

                        SourceBuilder yieldAssignmentSource = new SourceBuilder();
                        assignment.Emit(yieldAssignmentSource);
                        LocalYielding yieldAssignment =
                            new LocalYielding(yieldAssignmentSource.ToString());
                        insertionPoint = insertionPoint.Append(yieldAssignment);
                    }
                }
            }

            return insertionPoint;
        }