/// <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 => x.GetAstIdentifierForOutputIndex(0).Value); 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; }); controller.GenerateGraphSyncDataForCustomNode( this, WorkspaceModel.Nodes.Where(x => !(x is Symbol)), outputNodes, parameters); // Not update graph until Run // if (success) // controller.UpdateGraph(); }
private static Value ConvertAllResults(List<object> results) { //if there are multiple items in the results list //return a list type if (results.Count > 1) { FSharpList<Value> lst = FSharpList<Value>.Empty; //reverse the results list so our CONs list isn't backwards results.Reverse(); lst = results.Aggregate(lst, (current, result) => FSharpList<Value>.Cons(DynamoTypeConverter.ConvertToValue(result), current)); //the result will be a list of objects if any lists return Value.NewList(lst); } //otherwise, return a single value else { return DynamoTypeConverter.ConvertToValue(results.First()); } }
public CustomNodeDefinition( Guid functionId, string displayName="", IList<NodeModel> nodeModels=null) { if (functionId == Guid.Empty) throw new ArgumentException(@"FunctionId invalid.", "functionId"); nodeModels = nodeModels ?? new List<NodeModel>(); #region Find outputs // Find output elements for the node var outputs = nodeModels.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 = nodeModels.Where(node => node.IsTopMostNode); 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.FunctionId == functionId // 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 returnKeys = new List<string>(); foreach (var name in outNames) { int amt; if (nameDict.TryGetValue(name, out amt)) { nameDict[name] = amt - 1; returnKeys.Add(name == "" ? amt + ">" : name + amt); } else returnKeys.Add(name); } returnKeys.Reverse(); #endregion #region Find inputs //Find function entry point, and then compile var inputNodes = nodeModels.OfType<Symbol>().ToList(); var parameters = inputNodes.Select(x => new TypedParameter( x.GetAstIdentifierForOutputIndex(0).Value, x.Parameter.Type, x.Parameter.DefaultValue)); var displayParameters = inputNodes.Select(x => x.Parameter.Name); #endregion FunctionBody = nodeModels.Where(node => !(node is Symbol)); DisplayName = displayName; FunctionId = functionId; Parameters = parameters; ReturnKeys = returnKeys; DisplayParameters = displayParameters; OutputNodes = topMost.Select(x => x.Item2.GetAstIdentifierForOutputIndex(x.Item1)); DirectDependencies = nodeModels .OfType<Function>() .Select(node => node.Definition) .Where(def => def.FunctionId != functionId) .Distinct(); }