Esempio n. 1
0
        /// <summary>
        /// Stores given collection as the source of indexes and adds its unknown index into unknown operation.
        /// Also gets all indexes from the source collection and inserts it into target collection.
        ///
        /// This method is for the first phase of anaysis.
        /// </summary>
        /// <param name="sourceSnapshot">The source snapshot.</param>
        /// <param name="sourceIndex">Index of the source.</param>
        /// <param name="sourceContainer">The source container.</param>
        public void CollectIndexes(
            Snapshot sourceSnapshot,
            MemoryIndex sourceIndex,
            IReadonlyIndexContainer sourceContainer)
        {
            sources.Add(new Tuple <IReadonlyIndexContainer, Snapshot>(sourceContainer, sourceSnapshot));

            unknownOperation.Add(sourceContainer.UnknownIndex, sourceSnapshot);

            bool indexEquals = targetIndex.Equals(sourceIndex);

            foreach (var index in sourceContainer.Indexes)
            {
                MemoryIndex containerIndex;
                if (targetContainer.TryGetIndex(index.Key, out containerIndex))
                {
                    if (containerIndex == null && indexEquals)
                    {
                        writeableTargetContainer.AddIndex(index.Key, index.Value);
                        undefinedIndexes.Remove(index.Key);
                    }
                }
                else if (indexEquals)
                {
                    writeableTargetContainer.AddIndex(index.Key, index.Value);
                }
                else
                {
                    writeableTargetContainer.AddIndex(index.Key, null);
                    undefinedIndexes.Add(index.Key);
                }
            }
        }
Esempio n. 2
0
        /// <summary>
        /// Initializes a new instance of the <see cref="CopyIndexContainer"/> class.
        ///
        /// Content of given container is copied to the new container.
        /// </summary>
        /// <param name="container">The container.</param>
        public CopyIndexContainer(IReadonlyIndexContainer container)
        {
            unknownIndex = container.UnknownIndex;

            indexes = new Dictionary <string, MemoryIndex>();
            CollectionMemoryUtils.AddAll(indexes, container.Indexes);
        }
Esempio n. 3
0
        /// <summary>
        /// Creates merge operations for all indexes in the target collection. Source indexes for the operation are
        /// retreived from the source collections. When there is missing index in some collection the operation set
        /// to undefined.
        ///
        /// This method is for both phases of analysis.
        /// </summary>
        public void MergeContainers()
        {
            // Process all names which has unassociated index and creates one
            foreach (string indexName in undefinedIndexes)
            {
                writeableTargetContainer.AddIndex(indexName, targetIndex.CreateIndex(indexName));
            }

            foreach (var index in targetContainer.Indexes)
            {
                MergeOperation operation = new MergeOperation(index.Value);
                worker.addOperation(operation);

                if (isUndefined)
                {
                    operation.SetUndefined();
                }

                foreach (var source in sources)
                {
                    IReadonlyIndexContainer container = source.Item1;
                    Snapshot snapshot = source.Item2;

                    MemoryIndex containerIndex;
                    if (container.TryGetIndex(index.Key, out containerIndex))
                    {
                        operation.Add(containerIndex, snapshot);
                    }
                    else
                    {
                        operation.Add(container.UnknownIndex, snapshot);
                    }
                }
            }
        }
Esempio n. 4
0
        /// <summary>
        /// Cotinues traversing using specified segment in given index container.
        /// </summary>
        /// <param name="segment">The segment.</param>
        /// <param name="container">The container.</param>
        /// <param name="isMust">if set to <c>true</c> [is must].</param>
        private void processSegment(PathSegment segment, IReadonlyIndexContainer container, bool isMust = true)
        {
            if (segment.IsAny)
            {
                mayIndexesProcess.Add(container.UnknownIndex);
                addToMay(container.UnknownIndex);

                foreach (var index in container.Indexes)
                {
                    addToMay(index.Value);
                }
            }
            else if (segment.IsUnknown)
            {
                addToMay(container.UnknownIndex);
            }
            else if (segment.Names.Count == 1)
            {
                MemoryIndex processIndex;
                if (!container.TryGetIndex(segment.Names[0], out processIndex) && !snapshot.Structure.Locked)
                {
                    creatorVisitor.Name   = segment.Names[0];
                    creatorVisitor.IsMust = isMust;
                    segment.Accept(creatorVisitor);
                    processIndex = creatorVisitor.CreatedIndex;
                }

                if (processIndex != null)
                {
                    if (isMust)
                    {
                        addToMust(processIndex);
                    }
                    else
                    {
                        addToMay(processIndex);
                    }
                }
            }
            else
            {
                creatorVisitor.IsMust = false;

                foreach (String name in segment.Names)
                {
                    MemoryIndex processIndex;
                    if (!container.TryGetIndex(name, out processIndex) && !snapshot.Structure.Locked)
                    {
                        creatorVisitor.Name = name;
                        segment.Accept(creatorVisitor);
                        processIndex = creatorVisitor.CreatedIndex;
                    }

                    if (processIndex != null)
                    {
                        addToMay(processIndex);
                    }
                }
            }
        }
Esempio n. 5
0
        /// <summary>
        /// Collects the segment from structure.
        /// </summary>
        /// <param name="segment">The segment.</param>
        /// <param name="node">The node.</param>
        /// <param name="indexContainer">The index container.</param>
        /// <param name="isMust">if set to <c>true</c> [is must].</param>
        public void CollectSegmentFromStructure(PathSegment segment, CollectorNode node,
                                                IReadonlyIndexContainer indexContainer, bool isMust)
        {
            isMust = isMust && node.IsMust;

            if (segment.IsAny)
            {
                collectMemoryIndexAnyNode(indexContainer.UnknownIndex, node);

                foreach (var item in indexContainer.Indexes)
                {
                    collectMemoryIndexExpandedNode(item.Key, item.Value, node);
                }
            }
            else if (segment.IsUnknown)
            {
                collectMemoryIndexAnyNode(indexContainer.UnknownIndex, node);
            }
            else if (segment.Names.Count == 1)
            {
                string name = segment.Names[0];
                collectMemoryIndexNode(name, node, indexContainer, isMust);
            }
            else
            {
                foreach (string name in segment.Names)
                {
                    collectMemoryIndexNode(name, node, indexContainer, false);
                }
            }
        }
Esempio n. 6
0
        /// <summary>
        /// Enqueues the merge operation.
        /// </summary>
        /// <param name="childName">Name of the child.</param>
        /// <param name="operation">The operation.</param>
        /// <param name="targetContainerContext">The target container context.</param>
        /// <param name="childTreeNode">The child tree node.</param>
        /// <param name="alwaysDefined">if set to <c>true</c> [always defined].</param>
        private void enqueueMergeOperation(string childName, MergeOperation operation, ITargetContainerContext targetContainerContext, MemoryIndexTreeNode childTreeNode, bool alwaysDefined)
        {
            IReadonlyIndexContainer targetContainer = targetContainerContext.getSourceContainer();
            MemoryIndex             targetIndex;

            // Use index from target collection or crete and add it to the target collection
            if (!targetContainer.TryGetIndex(childName, out targetIndex))
            {
                targetIndex = createNewTargetIndex(targetContainerContext, childName);

                if (targetIndex == null)
                {
                    return;
                }
            }

            // Set parameters and add it to collection
            operation.TreeNode = childTreeNode;
            operation.SetTargetIndex(targetIndex);

            if (!alwaysDefined)
            {
                operation.SetUndefined();
            }

            operationQueue.AddLast(operation);
        }
Esempio n. 7
0
        private void createRepresentation(Snapshot snapshot, StringBuilder result, IReadonlyIndexContainer indexContainer)
        {
            createIndexRepresentation(snapshot, result, indexContainer.UnknownIndex, indexContainer.UnknownIndex.ToString());

            foreach (var item in indexContainer.Indexes)
            {
                MemoryIndex index = item.Value;
                createIndexRepresentation(snapshot, result, index, index.ToString());
            }
        }
Esempio n. 8
0
        private void createRepresentation(IReadonlyIndexContainer indexContainer)
        {
            createIndexRepresentation(indexContainer.UnknownIndex, indexContainer.UnknownIndex.ToString());

            foreach (var item in indexContainer.Indexes)
            {
                MemoryIndex index = item.Value;
                createIndexRepresentation(index, index.ToString());
            }
        }
Esempio n. 9
0
        /// <summary>
        /// Gets the or create control stack node.
        /// </summary>
        /// <param name="collector">The collector.</param>
        /// <param name="callLevel">The call level.</param>
        /// <returns>Node representing stack context on specified level.</returns>
        public ContainerCollectorNode GetOrCreateControlStackNode(TreeIndexCollector collector, int callLevel)
        {
            ContainerCollectorNode controlStackNode;

            if (!ControlStackNodes.TryGetValue(callLevel, out controlStackNode))
            {
                IReadonlyIndexContainer indexContainer = collector.Structure
                                                         .GetReadonlyStackContext(callLevel).ReadonlyControllVariables;
                controlStackNode = new ContainerCollectorNode(indexContainer);
                ControlStackNodes.Add(callLevel, controlStackNode);
            }

            return(controlStackNode);
        }
Esempio n. 10
0
        /// <summary>
        /// Main method of merge algorithm.
        ///
        /// iI first phase prepares new empty data collection. Then collects all root memory locations and
        /// prepares their operations. As the final step process all merge operations which traverses the
        /// memory tree and merges data from all source indexes.
        /// </summary>
        internal void Merge()
        {
            ContainerOperations[] collectVariables = new ContainerOperations[targetCallLevel + 1];
            ContainerOperations[] collectControl   = new ContainerOperations[targetCallLevel + 1];
            MergeOperation        returnOperation  = new MergeOperation();

            for (int x = 0; x <= targetCallLevel; x++)
            {
                IReadonlyIndexContainer variables = Structure.Readonly.GetReadonlyStackContext(x).ReadonlyVariables;
                collectVariables[x] = new ContainerOperations(this, variables, variables.UnknownIndex, variables.UnknownIndex);

                IReadonlyIndexContainer control = Structure.Readonly.GetReadonlyStackContext(x).ReadonlyControllVariables;
                collectControl[x] = new ContainerOperations(this, control, control.UnknownIndex, control.UnknownIndex);
            }

            foreach (Snapshot snapshot in sourceSnapshots)
            {
                for (int sourceLevel = 0, targetLevel = 0; targetLevel <= targetCallLevel; sourceLevel++, targetLevel++)
                {
                    if (sourceLevel == snapshot.CallLevel && snapshot.CallLevel != targetCallLevel)
                    {
                        if (isCallMerge)
                        {
                            break;
                        }
                        else
                        {
                            targetLevel = targetCallLevel;
                        }
                    }

                    IReadonlyIndexContainer variables = snapshot.Structure.Readonly.GetReadonlyStackContext(sourceLevel).ReadonlyVariables;
                    collectVariables[targetLevel].AddContainer(variables, snapshot);

                    IReadonlyIndexContainer control = snapshot.Structure.Readonly.GetReadonlyStackContext(sourceLevel).ReadonlyControllVariables;
                    collectControl[targetLevel].AddContainer(control, snapshot);
                }
            }

            mergeObjects();

            for (int x = 0; x <= targetCallLevel; x++)
            {
                collectVariables[x].MergeContainers();
                collectControl[x].MergeContainers();
                mergeTemporary(x);
            }

            processMerge();
        }
Esempio n. 11
0
        /// <summary>
        /// Initializes a new instance of the <see cref="ContainerOperations"/> class.
        /// </summary>
        /// <param name="worker">The worker.</param>
        /// <param name="targetContainer">The target container.</param>
        /// <param name="targetIndex">Index of the target.</param>
        /// <param name="unknownIndex">Index of the unknown.</param>
        public ContainerOperations(
            IMergeWorker worker,
            IWriteableIndexContainer targetContainer,
            MemoryIndex targetIndex,
            MemoryIndex unknownIndex)
        {
            this.targetContainer          = targetContainer;
            this.writeableTargetContainer = targetContainer;
            this.worker      = worker;
            this.targetIndex = targetIndex;

            unknownOperation = new MergeOperation(unknownIndex);
            worker.addOperation(unknownOperation);
        }
Esempio n. 12
0
        /// <summary>
        /// Gets the or create variable stack node.
        /// </summary>
        /// <param name="collector">The collector.</param>
        /// <param name="callLevel">The call level.</param>
        /// <returns></returns>
        public ContainerCollectorNode GetOrCreateVariableStackNode(TreeIndexCollector collector, int callLevel)
        {
            ContainerCollectorNode variableStackNode;

            if (!VariableStackNodes.TryGetValue(callLevel, out variableStackNode))
            {
                IReadonlyIndexContainer indexContainer = collector.Structure
                                                         .GetReadonlyStackContext(callLevel).ReadonlyVariables;

                variableStackNode = new ContainerCollectorNode(indexContainer);
                VariableStackNodes.Add(callLevel, variableStackNode);
            }

            return(variableStackNode);
        }
Esempio n. 13
0
        /// <summary>
        /// Enqueues the delete operation.
        /// </summary>
        /// <param name="childName">Name of the child.</param>
        /// <param name="operation">The operation.</param>
        /// <param name="targetContainerContext">The target container context.</param>
        /// <param name="childTreeNode">The child tree node.</param>
        private void enqueueDeleteOperation(string childName, MergeOperation operation, ITargetContainerContext targetContainerContext, MemoryIndexTreeNode childTreeNode)
        {
            IReadonlyIndexContainer targetContainer = targetContainerContext.getSourceContainer();
            MemoryIndex             targetIndex;

            if (targetContainer.TryGetIndex(childName, out targetIndex))
            {
                // Enque delete operation only if target index exists in paret snapshot
                operation.TreeNode = childTreeNode;
                operation.SetTargetIndex(targetIndex);
                operation.SetDeleteOperation();
                operationQueue.AddLast(operation);

                // Delete child from parent container
                targetContainerContext.getWriteableSourceContainer().RemoveIndex(childName);
            }
        }
Esempio n. 14
0
        /// <summary>
        /// Enqueues the merge unknown operation.
        /// </summary>
        /// <param name="targetContainerContext">The target container context.</param>
        /// <param name="anyNode">Any node.</param>
        /// <param name="sourceContainers">The source containers.</param>
        private void enqueueMergeUnknownOperation(ITargetContainerContext targetContainerContext, MemoryIndexTreeNode anyNode, List <ContainerContext> sourceContainers)
        {
            MergeOperation unknownOperation = new MergeOperation();

            foreach (ContainerContext containerContext in sourceContainers)
            {
                unknownOperation.Add(new MergeOperationContext(
                                         containerContext.IndexContainer.UnknownIndex, containerContext.SnapshotContext));
            }

            IReadonlyIndexContainer targetContainer = targetContainerContext.getSourceContainer();

            unknownOperation.TreeNode = anyNode;
            unknownOperation.SetTargetIndex(targetContainer.UnknownIndex);
            unknownOperation.SetUndefined();

            operationQueue.AddLast(unknownOperation);
        }
Esempio n. 15
0
        private void collectMemoryIndexNode(string name, CollectorNode node,
                                            IReadonlyIndexContainer indexContainer, bool isMust)
        {
            if (testAndProcessReturnedNode(name, node, isMust))
            {
                LocationCollectorNode nextNode;
                MemoryIndex           memoryIndex;
                if (indexContainer.TryGetIndex(name, out memoryIndex))
                {
                    nextNode = node.CreateMemoryIndexChild(name, memoryIndex);
                }
                else
                {
                    nextNode = node.CreateMemoryIndexChildFromAny(name, indexContainer.UnknownIndex);
                }

                nextNode.IsMust = isMust;
                AddNode(nextNode);
            }
        }
Esempio n. 16
0
        /// <summary>
        /// Cotinues traversing using specified segment in given index container.
        /// </summary>
        /// <param name="segment">The segment.</param>
        /// <param name="container">The container.</param>
        private void process(PathSegment segment, IReadonlyIndexContainer container)
        {
            if (segment.IsAny)
            {
                mustIndexesProcess.Add(container.UnknownIndex);
                foreach (var index in container.Indexes)
                {
                    mustIndexesProcess.Add(index.Value);
                }
            }
            else if (segment.IsUnknown)
            {
                mustIndexesProcess.Add(container.UnknownIndex);
            }
            else
            {
                bool isUnknown = false;
                foreach (String name in segment.Names)
                {
                    MemoryIndex index;
                    if (container.TryGetIndex(name, out index))
                    {
                        mustIndexesProcess.Add(index);
                    }
                    else
                    {
                        isUnknown = true;
                    }
                }

                if (isUnknown)
                {
                    IsDefined = false;
                    mustIndexesProcess.Add(container.UnknownIndex);
                }
            }
        }
Esempio n. 17
0
        /// <summary>
        /// Stores given collection as the source of indexes and adds its unknown index into unknown operation.
        /// Target collection is not modified.
        ///
        /// This method is for the second phase of anaysis.
        /// </summary>
        /// <param name="sourceContainer">The source container.</param>
        /// <param name="sourceSnapshot">The source snapshot.</param>
        public void AddContainer(IReadonlyIndexContainer sourceContainer, Snapshot sourceSnapshot)
        {
            sources.Add(new Tuple <IReadonlyIndexContainer, Snapshot>(sourceContainer, sourceSnapshot));

            unknownOperation.Add(sourceContainer.UnknownIndex, sourceSnapshot);
        }
Esempio n. 18
0
        /// <summary>
        /// Main method of merge algorithm.
        ///
        /// in first phase prepares new empty structure and data collections. Then collects all root memory locations
        /// and prepares their operations. As the final step process all merge operations which traverses the memory tree
        /// and creates new memory locations in target structure with the data from all source indexes.
        /// </summary>
        internal void Merge()
        {
            ContainerOperations[] collectVariables = new ContainerOperations[targetSnapshotCallLevel + 1];
            ContainerOperations[] collectControl   = new ContainerOperations[targetSnapshotCallLevel + 1];
            MergeOperation        returnOperation  = new MergeOperation();

            // Prepares empty structure for target snapshot
            for (int x = 0; x <= targetSnapshotCallLevel; x++)
            {
                writeableStrucure.AddLocalLevel();

                IWriteableIndexContainer variables = writeableStrucure.GetWriteableStackContext(x).WriteableVariables;
                collectVariables[x] = new ContainerOperations(this, variables, variables.UnknownIndex, variables.UnknownIndex);

                IWriteableIndexContainer control = writeableStrucure.GetWriteableStackContext(x).WriteableControllVariables;
                collectControl[x] = new ContainerOperations(this, control, control.UnknownIndex, control.UnknownIndex);
            }

            // Collects all objects and root locations from the source objects
            foreach (Snapshot snapshot in sourceSnapshots)
            {
                collectObjects(snapshot);

                for (int sourceLevel = 0, targetLevel = 0; targetLevel <= targetSnapshotCallLevel; sourceLevel++, targetLevel++)
                {
                    // Local levels of snaphot has to be merged together no matter to call level of each snapshot.
                    if (sourceLevel == snapshot.CallLevel && snapshot.CallLevel != targetSnapshotCallLevel)
                    {
                        if (isCallMerge)
                        {
                            // When this is the call merge the local level is forgotten
                            break;
                        }
                        else
                        {
                            targetLevel = targetSnapshotCallLevel;
                        }
                    }

                    // Gets all root locations
                    IWriteableIndexContainer targetVariables = writeableStrucure.GetWriteableStackContext(targetLevel).WriteableVariables;
                    IReadonlyIndexContainer  sourceVariables = snapshot.Structure.Readonly.GetReadonlyStackContext(sourceLevel).ReadonlyVariables;
                    collectVariables[targetLevel].CollectIndexes(snapshot, targetVariables.UnknownIndex, sourceVariables);

                    IWriteableIndexContainer targetControlls = writeableStrucure.GetWriteableStackContext(targetLevel).WriteableControllVariables;
                    IReadonlyIndexContainer  sourceControlls = snapshot.Structure.Readonly.GetReadonlyStackContext(sourceLevel).ReadonlyControllVariables;
                    collectControl[targetLevel].CollectIndexes(snapshot, targetControlls.UnknownIndex, sourceControlls);
                    collectTemporary(snapshot, sourceLevel, targetLevel);
                }

                foreach (var name in snapshot.Structure.Readonly.GetFunctions())
                {
                    foreach (var decl in snapshot.Structure.Readonly.GetFunction(name))
                    {
                        writeableStrucure.AddFunctiondeclaration(name, decl);
                    }
                }

                foreach (var name in snapshot.Structure.Readonly.GetClasses())
                {
                    foreach (var decl in snapshot.Structure.Readonly.GetClass(name))
                    {
                        writeableStrucure.AddClassDeclaration(name, decl);
                    }
                }

                // When is it call merge remember which arrays was forgotten in order to support arrays in returns
                if (isCallMerge)
                {
                    foreach (AssociativeArray array in snapshot.Structure.Readonly.ReadonlyLocalContext.ReadonlyArrays)
                    {
                        writeableStrucure.AddCallArray(array, snapshot);
                    }
                }
            }

            mergeObjects();

            // Prepares operations for all root locations
            for (int x = 0; x <= targetSnapshotCallLevel; x++)
            {
                collectVariables[x].MergeContainers();
                collectControl[x].MergeContainers();
                mergeTemporary(x);
            }

            processMerge();

            // Build aliases
            foreach (var alias in memoryAliases)
            {
                writeableStrucure.SetAlias(alias.Key, alias.Value.Build(writeableStrucure));
            }
        }
Esempio n. 19
0
 public ContainerCollectorNode(IReadonlyIndexContainer indexContainer)
 {
     this.indexContainer = indexContainer;
     IsMust = true;
 }
Esempio n. 20
0
 /// <summary>
 /// Initializes a new instance of the <see cref="ContainerContext"/> class.
 /// </summary>
 /// <param name="context">The context.</param>
 /// <param name="indexContainer">The index container.</param>
 /// <param name="operationType">Type of the operation.</param>
 public ContainerContext(SnapshotContext context, IReadonlyIndexContainer indexContainer, MergeOperationType operationType = MergeOperationType.ChangedOnly)
 {
     this.SnapshotContext = context;
     this.IndexContainer  = indexContainer;
     this.OperationType   = operationType;
 }
Esempio n. 21
0
        /// <summary>
        /// Creates the and enqueue operations.
        /// </summary>
        /// <param name="targetContainerContext">The target container context.</param>
        /// <param name="treeNode">The tree node.</param>
        /// <param name="sourceContainers">The source containers.</param>
        /// <param name="alwaysDefined">if set to <c>true</c> [always defined].</param>
        private void createAndEnqueueOperations(
            ITargetContainerContext targetContainerContext,
            MemoryIndexTreeNode treeNode,
            List <ContainerContext> sourceContainers,
            bool alwaysDefined)
        {
            IReadonlyIndexContainer targetContainer = targetContainerContext.getSourceContainer();

            // Creates and enques merge operations for all child nodes of given node
            foreach (var childNode in treeNode.ChildNodes)
            {
                string childName = childNode.Key;
                MemoryIndexTreeNode childTreeNode = childNode.Value;

                MergeOperation operation      = new MergeOperation();
                bool           isChildDefined = collectIndexes(childName, sourceContainers, operation);

                if (isChildDefined)
                {
                    // Child is defined at least in one collection - enqueue merge operation

                    MemoryIndex targetIndex;
                    // Use index from target collection or crete and add it to the target collection
                    if (!targetContainer.TryGetIndex(childName, out targetIndex))
                    {
                        targetIndex = createNewTargetIndex(targetContainerContext, childName);

                        if (targetIndex == null)
                        {
                            continue;
                        }
                    }

                    // Set parameters and add it to collection
                    operation.TreeNode = childTreeNode;
                    operation.SetTargetIndex(targetIndex);

                    if (!alwaysDefined)
                    {
                        operation.SetUndefined();
                    }

                    operationQueue.AddLast(operation);
                }
                else
                {
                    // Child is not defined - enqueue delete operation

                    MemoryIndex targetIndex;
                    if (targetContainer.TryGetIndex(childName, out targetIndex))
                    {
                        // Enque delete operation only if target index exists in paret snapshot
                        operation.TreeNode = childTreeNode;
                        operation.SetTargetIndex(targetIndex);
                        operation.SetDeleteOperation();
                        operationQueue.AddLast(operation);

                        deleteChild(targetContainerContext, childName);
                    }
                }
            }

            // Enqueue merge operation for unknown index if is defined
            if (treeNode.AnyChild != null)
            {
                MergeOperation unknownOperation = new MergeOperation();

                foreach (ContainerContext containerContext in sourceContainers)
                {
                    unknownOperation.Add(new MergeOperationContext(
                                             containerContext.IndexContainer.UnknownIndex, containerContext.SnapshotContext));
                }

                unknownOperation.TreeNode = treeNode.AnyChild;
                unknownOperation.SetTargetIndex(targetContainer.UnknownIndex);
                unknownOperation.SetUndefined();

                operationQueue.AddLast(unknownOperation);
            }
        }