/// <summary> /// DynamoModel calls this method prior to scheduling a graph update for /// the home workspace. This method is called to schedule custom node /// compilation since the home workspace update may depend on it. Any /// updates to a CustomNodeDefinition will cause GraphSyncData to be added /// to "pendingCustomNodeSyncData" queue. /// </summary> /// <param name="scheduler">The scheduler on which custom node compilation /// task can be scheduled.</param> /// internal void ProcessPendingCustomNodeSyncData(DynamoScheduler scheduler) { while (pendingCustomNodeSyncData.Count > 0) { var initParams = new CompileCustomNodeParams() { SyncData = pendingCustomNodeSyncData.Dequeue(), EngineController = this }; var compileTask = new CompileCustomNodeAsyncTask(scheduler); if (compileTask.Initialize(initParams)) scheduler.ScheduleForExecution(compileTask); } }
/// <summary> /// Compiles this custom node definition, updating all UI instances to match /// inputs and outputs and registering new definition with the EngineController. /// </summary> public void Compile(DynamoModel dynamoModel, EngineController controller) { // If we are loading dyf file, dont compile it until all nodes are loaded // otherwise some intermediate function defintions will be created. // TODO: This is a hack, in reality we should be preventing this from being called at the Workspace.RequestSync() level --SJE if (IsBeingLoaded || IsProxy) return; #region Outputs and Inputs and UI updating #region Find outputs // Find output elements for the node List<Output> outputs = WorkspaceModel.Nodes.OfType<Output>().ToList(); var topMost = new List<Tuple<int, NodeModel>>(); List<string> outNames; // if we found output nodes, add select their inputs // these will serve as the function output if (outputs.Any()) { topMost.AddRange( outputs.Where(x => x.HasInput(0)).Select(x => Tuple.Create(0, x as NodeModel))); outNames = outputs.Select(x => x.Symbol).ToList(); } else { outNames = new List<string>(); // if there are no explicitly defined output nodes // get the top most nodes and set THEM as the output IEnumerable<NodeModel> topMostNodes = WorkspaceModel.GetTopMostNodes(); var rtnPorts = //Grab multiple returns from each node topMostNodes.SelectMany( topNode => //If the node is a recursive instance... topNode is Function && (topNode as Function).Definition == this // infinity output ? new[] { new { portIndex = 0, node = topNode, name = "∞" } } // otherwise, grab all ports with connected outputs and package necessary info : topNode.OutPortData .Select( (port, i) => new { portIndex = i, node = topNode, name = port.NickName }) .Where(x => !topNode.HasOutput(x.portIndex))); foreach (var rtnAndIndex in rtnPorts.Select((rtn, i) => new { rtn, idx = i })) { topMost.Add(Tuple.Create(rtnAndIndex.rtn.portIndex, rtnAndIndex.rtn.node)); outNames.Add(rtnAndIndex.rtn.name ?? rtnAndIndex.idx.ToString()); } } var nameDict = new Dictionary<string, int>(); foreach (var name in outNames) { if (nameDict.ContainsKey(name)) nameDict[name]++; else nameDict[name] = 0; } nameDict = nameDict.Where(x => x.Value != 0).ToDictionary(x => x.Key, x => x.Value); outNames.Reverse(); var keys = new List<string>(); foreach (var name in outNames) { int amt; if (nameDict.TryGetValue(name, out amt)) { nameDict[name] = amt - 1; keys.Add(name == "" ? amt + ">" : name + amt); } else keys.Add(name); } keys.Reverse(); ReturnKeys = keys; #endregion //Find function entry point, and then compile var inputNodes = WorkspaceModel.Nodes.OfType<Symbol>().ToList(); var parameters = inputNodes.Select(x => string.IsNullOrEmpty(x.InputSymbol) ? x.AstIdentifierForPreview.Value: x.InputSymbol); Parameters = inputNodes.Select(x => x.InputSymbol); //Update existing function nodes which point to this function to match its changes var customNodeInstances = dynamoModel.AllNodes .OfType<Function>() .Where(el => el.Definition != null && el.Definition == this); foreach (var node in customNodeInstances) node.ResyncWithDefinition(); //Call OnSave for all saved elements foreach (var node in WorkspaceModel.Nodes) node.OnSave(); #endregion var outputNodes = topMost.Select((x) => { var n = x.Item2.GetAstIdentifierForOutputIndex(x.Item1); return n as AssociativeNode; }); #if ENABLE_DYNAMO_SCHEDULER var initParams = new CompileCustomNodeParams() { EngineController = controller, Definition = this, Nodes = WorkspaceModel.Nodes.Where(x => !(x is Symbol)), Parameters = parameters, Outputs = outputNodes }; // Schedule the compilation of CustomNodeDefinition, we are // not interested in when it will be completed, so no callback. var scheduler = dynamoModel.Scheduler; var task = new CompileCustomNodeAsyncTask(scheduler); if (task.Initialize(initParams)) scheduler.ScheduleForExecution(task); #else controller.GenerateGraphSyncDataForCustomNode( this, WorkspaceModel.Nodes.Where(x => !(x is Symbol)), outputNodes, parameters); #endif // Not update graph until Run // if (success) // controller.UpdateGraph(); }