/// <summary> /// Updates all blocks related to a specific procedure with respect to name, arguments, and /// whether the definition can contain a statement sequence. If any of the optional arguments are /// null, the existing values from the blocks are used. /// </summary> /// <param name="originalProcedureName">The name of the procedure, before this method.</param> /// <param name="updatedProcedure">The info with which to update procedure mutators.</param> /// <param name="argIndexUpdates">A list of mappings from original argument index to new index.</param> public void MutateProcedure(string originalProcedureName, Procedure updatedProcedure, List <ProcedureArgumentIndexUpdate> argIndexUpdates = null) { Block definition = GetDefinitionBlock(originalProcedureName); if (definition == null) { throw new Exception("Unknown procedure \"" + originalProcedureName + "\""); } List <Block> procedureCalls = GetCallers(originalProcedureName); ProcedureDefinitionMutator definitionMutator = definition.Mutator as ProcedureDefinitionMutator; Procedure oldInfo = definitionMutator.ProcedureInfo; mNameMgr.RemoveDistinctName(originalProcedureName); string newProcedureName = mNameMgr.GetDistinctName(updatedProcedure.Name); bool isFuncRename = !newProcedureName.Equals(originalProcedureName); if (isFuncRename) { mProcedureDefinitions.Remove(originalProcedureName); mProcedureDefinitions[newProcedureName] = definition; mProcedureCallers.Remove(originalProcedureName); mProcedureCallers[newProcedureName] = procedureCalls; } List <string> newArgs = updatedProcedure.Arguments; for (int i = 0; i < newArgs.Count; i++) { string argName = newArgs[i]; if (!Names.IsSafe(argName)) { throw new Exception("Invalid variable name \"" + argName + "\" " + "(argument #" + i + " )"); } // create new variable if (!mWorkspace.HasVariable(argName)) { mWorkspace.CreateVariable(argName); } } definitionMutator.Mutate(updatedProcedure); //mutate each procedure call foreach (Block procRef in procedureCalls) { ProcedureCallMutator callMutator = procRef.Mutator as ProcedureCallMutator; int oldArgCount = callMutator.GetArgumentNameList().Count; Block[] oldValues = new Block[oldArgCount]; //disconnect prior value blocks for (int i = 0; i < oldArgCount; i++) { Input argInput = callMutator.GetArgumenInput(i); Block valueBlock = argInput.ConnectedBlock; if (valueBlock != null) { oldValues[i] = valueBlock; argInput.Connection.Disconnect(); } } callMutator.Mutate(updatedProcedure); //reconnect any blocks to orginal inputs if (argIndexUpdates != null) { foreach (ProcedureArgumentIndexUpdate indexUpdate in argIndexUpdates) { Block originalValue = oldValues[indexUpdate.Before]; if (originalValue != null) { Input argInput = callMutator.GetArgumenInput(indexUpdate.After); argInput.Connection.Connect(originalValue.OutputConnection); } } } } FireUpdate(new ProcedureUpdateData(oldInfo, updatedProcedure)); }