private Dictionary<int, INode> buildPartialMultiOut(IEnumerable<string> portNames, List<Tuple<string, INode>> connections, List<string> partials) { return OutPortData.Select((d, i) => new { Index = i, Data = d }).ToDictionary( data => data.Index, data => { var node = Compile(portNames); foreach (var partial in partials) node.ConnectInput(partial, new SymbolNode(partial)); var accessor = new ExternalFunctionNode(FScheme.Get, new[] { "idx", "list" }); accessor.ConnectInput("list", node); accessor.ConnectInput("idx", new NumberNode(data.Index)); var outerNode = new AnonymousFunctionNode(partials, accessor); if (connections.Any()) { outerNode = new AnonymousFunctionNode(connections.Select(x => x.Item1), outerNode); foreach (var connection in connections) { node.ConnectInput(connection.Item1, new SymbolNode(connection.Item1)); outerNode.ConnectInput(connection.Item1, connection.Item2); } } return outerNode as INode; }); }
//TODO: do all of this as the Ui is modified, simply return this? /// <summary> /// Builds an INode out of this Element. Override this or Compile() if you want complete control over this Element's /// execution. /// </summary> /// <returns>The INode representation of this Element.</returns> protected internal virtual INode Build(Dictionary<dynNode, Dictionary<int, INode>> preBuilt, int outPort) { Dictionary<int, INode> result; if (preBuilt.TryGetValue(this, out result)) return result[outPort]; //Fetch the names of input ports. var portNames = InPortData.Zip(Enumerable.Range(0, InPortData.Count), (x, i) => x.NickName + i); //Compile the procedure for this node. InputNode node = Compile(portNames); //Is this a partial application? var partial = false; var partialSymList = new List<string>(); //For each index in InPortData //for (int i = 0; i < InPortData.Count; i++) foreach (var data in Enumerable.Range(0, InPortData.Count).Zip(portNames, (data, name) => new { Index=data, Name=name })) { //Fetch the corresponding port //var port = InPorts[i]; Tuple<int, dynNode> input; //If this port has connectors... //if (port.Connectors.Any()) if (TryGetInput(data.Index, out input)) { //Compile input and connect it node.ConnectInput(data.Name, input.Item2.Build(preBuilt, input.Item1)); } else //othwise, remember that this is a partial application { partial = true; partialSymList.Add(data.Name); } } var nodes = new Dictionary<int, INode>(); if (OutPortData.Count > 1) { foreach (var data in partialSymList) node.ConnectInput(data, new SymbolNode(data)); InputNode prev = node; int prevIndex = 0; foreach (var data in Enumerable.Range(0, OutPortData.Count).Zip(OutPortData, (i, d) => new { Index = i, Data = d })) { if (HasOutput(data.Index)) { if (data.Index > 0) { var diff = data.Index - prevIndex; InputNode restNode; if (diff > 1) { restNode = new ExternalFunctionNode(FScheme.Drop, new List<string>() { "amt", "list" }); restNode.ConnectInput("amt", new NumberNode(diff)); restNode.ConnectInput("list", prev); } else { restNode = new ExternalFunctionNode(FScheme.Cdr, new List<string>() { "list" }); restNode.ConnectInput("list", prev); } prev = restNode; prevIndex = data.Index; } var firstNode = new ExternalFunctionNode(FScheme.Car, new List<string>() { "list" }); firstNode.ConnectInput("list", prev); if (partial) nodes[data.Index] = new AnonymousFunctionNode(partialSymList, firstNode); else nodes[data.Index] = firstNode; } } } else { nodes[outPort] = node; } //If this is a partial application, then remember not to re-eval. if (partial) { RequiresRecalc = false; } preBuilt[this] = nodes; //And we're done return nodes[outPort]; }
private Dictionary<int, INode> buildMultiOut(IEnumerable<string> portNames, IEnumerable<Tuple<string, INode>> connections) { InputNode node = Compile(portNames); foreach (var connection in connections) node.ConnectInput(connection.Item1, connection.Item2); InputNode prev = node; return OutPortData.Select((d, i) => new { Index = i, Data = d }).ToDictionary( data => data.Index, data => { if (data.Index > 0) { var rest = new ExternalFunctionNode(FScheme.Cdr, new[] { "list" }); rest.ConnectInput("list", prev); prev = rest; } var firstNode = new ExternalFunctionNode(FScheme.Car, new[] { "list" }); firstNode.ConnectInput("list", prev); return firstNode as INode; }); }
private static FScheme.Expression CompileFunction( FunctionDefinition definition ) { if (definition == null) return null; // Get the internal nodes for the function dynWorkspace functionWorkspace = definition.Workspace; #region Find outputs // Find output elements for the node IEnumerable<dynNode> outputs = functionWorkspace.Nodes.Where(x => x is dynOutput); var topMost = new List<Tuple<int, dynNode>>(); IEnumerable<string> outputNames; // 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 => x.Inputs[0])); outputNames = outputs.Select(x => (x as dynOutput).Symbol); } else { // if there are no explicitly defined output nodes // get the top most nodes and set THEM as tht output IEnumerable<dynNode> topMostNodes = functionWorkspace.GetTopMostNodes(); var outNames = new List<string>(); foreach (dynNode topNode in topMostNodes) { foreach (int output in Enumerable.Range(0, topNode.OutPortData.Count)) { if (!topNode.HasOutput(output)) { topMost.Add(Tuple.Create(output, topNode)); outNames.Add(topNode.OutPortData[output].NickName); } } } outputNames = outNames; } #endregion // color the node to define its connectivity foreach (var ele in topMost) { ele.Item2.NodeUI.ValidateConnections(); } //Find function entry point, and then compile the function and add it to our environment IEnumerable<dynNode> variables = functionWorkspace.Nodes.Where(x => x is dynSymbol); IEnumerable<string> inputNames = variables.Select(x => (x as dynSymbol).Symbol); INode top; var buildDict = new Dictionary<dynNode, Dictionary<int, INode>>(); if (topMost.Count > 1) { InputNode node = new ExternalFunctionNode( FScheme.Value.NewList, Enumerable.Range(0, topMost.Count).Select(x => x.ToString())); int i = 0; foreach (var topNode in topMost) { string inputName = i.ToString(); node.ConnectInput(inputName, topNode.Item2.Build(buildDict, topNode.Item1)); i++; } top = node; } else top = topMost[0].Item2.BuildExpression(buildDict); // if the node has any outputs, we create a BeginNode in order to evaluate all of them // sequentially (begin evaluates a list of expressions) if (outputs.Any()) { var beginNode = new BeginNode(); List<dynNode> hangingNodes = functionWorkspace.GetTopMostNodes().ToList(); foreach (var tNode in hangingNodes.Select((x, index) => new { Index = index, Node = x })) { beginNode.AddInput(tNode.Index.ToString()); beginNode.ConnectInput(tNode.Index.ToString(), tNode.Node.Build(buildDict, 0)); } beginNode.AddInput(hangingNodes.Count.ToString()); beginNode.ConnectInput(hangingNodes.Count.ToString(), top); top = beginNode; } // make the anonymous function FScheme.Expression expression = Utils.MakeAnon(variables.Select(x => x.NodeUI.GUID.ToString()), top.Compile()); return expression; }
public FScheme.Expression Compile() { IEnumerable<string> inputNames = null; IEnumerable<string> outputNames = null; // Get the internal nodes for the function WorkspaceModel functionWorkspace = this.WorkspaceModel; #region Find outputs // Find output elements for the node List<Output> outputs = functionWorkspace.Nodes.OfType<Output>().ToList(); var topMost = new List<Tuple<int, NodeModel>>(); // 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 => x.Inputs[0])); outputNames = outputs.Select(x => x.Symbol); } else { // if there are no explicitly defined output nodes // get the top most nodes and set THEM as the output IEnumerable<NodeModel> topMostNodes = functionWorkspace.GetTopMostNodes(); NodeModel infinite = null; var outNames = new List<string>(); foreach (NodeModel topNode in topMostNodes) { if (topNode is Function && (topNode as Function).Definition == this) { infinite = topNode; continue; } foreach (int output in Enumerable.Range(0, topNode.OutPortData.Count)) { if (!topNode.HasOutput(output)) { topMost.Add(Tuple.Create(output, topNode)); outNames.Add(topNode.OutPortData[output].NickName); } } } if (infinite != null && outNames.Count == 0) { topMost.Add(Tuple.Create(0, infinite)); outNames.Add("∞"); } outputNames = outNames; } #endregion // color the node to define its connectivity foreach (var ele in topMost) { ele.Item2.ValidateConnections(); } //Find function entry point, and then compile var variables = functionWorkspace.Nodes.OfType<Symbol>().ToList(); inputNames = variables.Select(x => x.InputSymbol); //Update existing function nodes which point to this function to match its changes dynSettings.Controller.DynamoModel.AllNodes .OfType<Function>() .Where(el => el.Definition != null && el.Definition.FunctionId == this.FunctionId) .ToList() .ForEach(node => { node.SetInputs(inputNames); node.SetOutputs(outputNames); node.RegisterAllPorts(); }); //Call OnSave for all saved elements functionWorkspace.Nodes.ToList().ForEach(x => x.onSave()); INode top; var buildDict = new Dictionary<NodeModel, Dictionary<int, INode>>(); if (topMost.Count > 1) { InputNode node = new ExternalFunctionNode(FScheme.Value.NewList); int i = 0; foreach (var topNode in topMost) { string inputName = i.ToString(CultureInfo.InvariantCulture); node.AddInput(inputName); node.ConnectInput(inputName, new BeginNode()); try { var exp = topNode.Item2.Build(buildDict, topNode.Item1); node.ConnectInput(inputName, exp); } catch { } i++; } top = node; } else if (topMost.Count == 1) { top = topMost[0].Item2.Build(buildDict, topMost[0].Item1); } else { // if the custom node is empty, it will initially be an empty begin top = new BeginNode(); } // if the node has any outputs, we create a BeginNode in order to evaluate all of them // sequentially (begin evaluates a list of expressions) if (outputs.Any()) { var beginNode = new BeginNode(); List<NodeModel> hangingNodes = functionWorkspace.GetHangingNodes().ToList(); foreach (var tNode in hangingNodes.Select((x, index) => new { Index = index, Node = x })) { beginNode.AddInput(tNode.Index.ToString(CultureInfo.InvariantCulture)); beginNode.ConnectInput( tNode.Index.ToString(CultureInfo.InvariantCulture), tNode.Node.Build(buildDict, 0)); } beginNode.AddInput(hangingNodes.Count.ToString(CultureInfo.InvariantCulture)); beginNode.ConnectInput(hangingNodes.Count.ToString(CultureInfo.InvariantCulture), top); top = beginNode; } // make the anonymous function FScheme.Expression expression = Utils.MakeAnon( variables.Select(x => x.GUID.ToString()), top.Compile()); return expression; }
public static FScheme.Expression CompileFunction(FunctionDefinition definition, ref IEnumerable <string> inputNames, ref IEnumerable <string> outputNames) { if (definition == null) { return(null); } // Get the internal nodes for the function dynWorkspaceModel functionWorkspace = definition.Workspace; #region Find outputs // Find output elements for the node List <dynOutput> outputs = functionWorkspace.Nodes.OfType <dynOutput>().ToList(); var topMost = new List <Tuple <int, dynNodeModel> >(); // 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 => x.Inputs[0])); outputNames = outputs.Select(x => x.Symbol); } else { // if there are no explicitly defined output nodes // get the top most nodes and set THEM as the output IEnumerable <dynNodeModel> topMostNodes = functionWorkspace.GetTopMostNodes(); var outNames = new List <string>(); foreach (dynNodeModel topNode in topMostNodes) { foreach (int output in Enumerable.Range(0, topNode.OutPortData.Count)) { if (!topNode.HasOutput(output)) { topMost.Add(Tuple.Create(output, topNode)); outNames.Add(topNode.OutPortData[output].NickName); } } } outputNames = outNames; } #endregion // color the node to define its connectivity foreach (var ele in topMost) { ele.Item2.ValidateConnections(); } //Find function entry point, and then compile the function and add it to our environment IEnumerable <dynNodeModel> variables = functionWorkspace.Nodes.Where(x => x is dynSymbol); inputNames = variables.Select(x => (x as dynSymbol).Symbol); INode top; var buildDict = new Dictionary <dynNodeModel, Dictionary <int, INode> >(); if (topMost.Count > 1) { InputNode node = new ExternalFunctionNode(FScheme.Value.NewList); int i = 0; foreach (var topNode in topMost) { string inputName = i.ToString(); node.AddInput(inputName); node.ConnectInput(inputName, new BeginNode()); try { var exp = topNode.Item2.Build(buildDict, topNode.Item1); node.ConnectInput(inputName, exp); } catch { } i++; } top = node; } else if (topMost.Count == 1) { top = topMost[0].Item2.BuildExpression(buildDict); } else { // if the custom node is empty, it will initially be an empty begin top = new BeginNode(); } // if the node has any outputs, we create a BeginNode in order to evaluate all of them // sequentially (begin evaluates a list of expressions) if (outputs.Any()) { var beginNode = new BeginNode(); List <dynNodeModel> hangingNodes = functionWorkspace.GetHangingNodes().ToList(); foreach (var tNode in hangingNodes.Select((x, index) => new { Index = index, Node = x })) { beginNode.AddInput(tNode.Index.ToString()); beginNode.ConnectInput(tNode.Index.ToString(), tNode.Node.Build(buildDict, 0)); } beginNode.AddInput(hangingNodes.Count.ToString()); beginNode.ConnectInput(hangingNodes.Count.ToString(), top); top = beginNode; } // make the anonymous function FScheme.Expression expression = Utils.MakeAnon(variables.Select(x => x.GUID.ToString()), top.Compile()); return(expression); }
public FScheme.Expression Compile() { IEnumerable <string> inputNames = null; IEnumerable <string> outputNames = null; // Get the internal nodes for the function WorkspaceModel functionWorkspace = this.WorkspaceModel; #region Find outputs // Find output elements for the node List <Output> outputs = functionWorkspace.Nodes.OfType <Output>().ToList(); var topMost = new List <Tuple <int, NodeModel> >(); // 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 => x.Inputs[0])); outputNames = outputs.Select(x => x.Symbol); } else { // if there are no explicitly defined output nodes // get the top most nodes and set THEM as the output IEnumerable <NodeModel> topMostNodes = functionWorkspace.GetTopMostNodes(); NodeModel infinite = null; var outNames = new List <string>(); foreach (NodeModel topNode in topMostNodes) { if (topNode is Function && (topNode as Function).Definition == this) { infinite = topNode; continue; } foreach (int output in Enumerable.Range(0, topNode.OutPortData.Count)) { if (!topNode.HasOutput(output)) { topMost.Add(Tuple.Create(output, topNode)); outNames.Add(topNode.OutPortData[output].NickName); } } } if (infinite != null && outNames.Count == 0) { topMost.Add(Tuple.Create(0, infinite)); outNames.Add("∞"); } outputNames = outNames; } #endregion // color the node to define its connectivity foreach (var ele in topMost) { ele.Item2.ValidateConnections(); } //Find function entry point, and then compile var variables = functionWorkspace.Nodes.OfType <Symbol>().ToList(); inputNames = variables.Select(x => x.InputSymbol); //Update existing function nodes which point to this function to match its changes dynSettings.Controller.DynamoModel.AllNodes .OfType <Function>() .Where(el => el.Definition != null && el.Definition.FunctionId == this.FunctionId) .ToList() .ForEach(node => { node.SetInputs(inputNames); node.SetOutputs(outputNames); node.RegisterAllPorts(); }); //Call OnSave for all saved elements functionWorkspace.Nodes.ToList().ForEach(x => x.onSave()); INode top; var buildDict = new Dictionary <NodeModel, Dictionary <int, INode> >(); if (topMost.Count > 1) { InputNode node = new ExternalFunctionNode(FScheme.Value.NewList); int i = 0; foreach (var topNode in topMost) { string inputName = i.ToString(CultureInfo.InvariantCulture); node.AddInput(inputName); node.ConnectInput(inputName, new BeginNode()); try { var exp = topNode.Item2.Build(buildDict, topNode.Item1); node.ConnectInput(inputName, exp); } catch { } i++; } top = node; } else if (topMost.Count == 1) { top = topMost[0].Item2.Build(buildDict, topMost[0].Item1); } else { // if the custom node is empty, it will initially be an empty begin top = new BeginNode(); } // if the node has any outputs, we create a BeginNode in order to evaluate all of them // sequentially (begin evaluates a list of expressions) if (outputs.Any()) { var beginNode = new BeginNode(); List <NodeModel> hangingNodes = functionWorkspace.GetHangingNodes().ToList(); foreach (var tNode in hangingNodes.Select((x, index) => new { Index = index, Node = x })) { beginNode.AddInput(tNode.Index.ToString(CultureInfo.InvariantCulture)); beginNode.ConnectInput( tNode.Index.ToString(CultureInfo.InvariantCulture), tNode.Node.Build(buildDict, 0)); } beginNode.AddInput(hangingNodes.Count.ToString(CultureInfo.InvariantCulture)); beginNode.ConnectInput(hangingNodes.Count.ToString(CultureInfo.InvariantCulture), top); top = beginNode; } // make the anonymous function FScheme.Expression expression = Utils.MakeAnon( variables.Select(x => x.GUID.ToString()), top.Compile()); return(expression); }
//TODO: do all of this as the Ui is modified, simply return this? /// <summary> /// Builds an INode out of this Element. Override this or Compile() if you want complete control over this Element's /// execution. /// </summary> /// <returns>The INode representation of this Element.</returns> protected internal virtual INode Build(Dictionary<dynNodeModel, Dictionary<int, INode>> preBuilt, int outPort) { //Debug.WriteLine("Building node..."); Dictionary<int, INode> result; if (preBuilt.TryGetValue(this, out result)) return result[outPort]; //Fetch the names of input ports. var portNames = InPortData.Zip(Enumerable.Range(0, InPortData.Count), (x, i) => x.NickName + i).ToList(); //Compile the procedure for this node. InputNode node = Compile(portNames); //Is this a partial application? var partial = false; var connections = new List<Tuple<string, INode>>(); var partialSymList = new List<string>(); //For each index in InPortData //for (int i = 0; i < InPortData.Count; i++) foreach (var data in Enumerable.Range(0, InPortData.Count).Zip(portNames, (data, name) => new { Index = data, Name = name })) { //Fetch the corresponding port //var port = InPorts[i]; Tuple<int, dynNodeModel> input; //If this port has connectors... //if (port.Connectors.Any()) if (TryGetInput(data.Index, out input)) { //Debug.WriteLine(string.Format("Connecting input {0}", data.Name)); //Compile input and connect it connections.Add(Tuple.Create(data.Name, input.Item2.Build(preBuilt, input.Item1))); } else //othwise, remember that this is a partial application { partial = true; node.ConnectInput(data.Name, new SymbolNode(data.Name)); partialSymList.Add(data.Name); } } var nodes = new Dictionary<int, INode>(); if (OutPortData.Count > 1) { if (partial) { foreach (var connection in connections) { node.ConnectInput(connection.Item1, new SymbolNode(connection.Item1)); } } else { foreach (var connection in connections) { node.ConnectInput(connection.Item1, connection.Item2); } } InputNode prev = node; int prevIndex = 0; foreach (var data in OutPortData.Select((d, i) => new { Index = i, Data = d })) { if (HasOutput(data.Index)) { if (data.Index > 0) { var diff = data.Index - prevIndex; InputNode restNode; if (diff > 1) { restNode = new ExternalFunctionNode(FScheme.Drop, new[] { "amt", "list" }); restNode.ConnectInput("amt", new NumberNode(diff)); restNode.ConnectInput("list", prev); } else { restNode = new ExternalFunctionNode(FScheme.Cdr, new[] { "list" }); restNode.ConnectInput("list", prev); } prev = restNode; prevIndex = data.Index; } var firstNode = new ExternalFunctionNode(FScheme.Car, new[] { "list" }) as InputNode; firstNode.ConnectInput("list", prev); if (partial) { var outerNode = new AnonymousFunctionNode(partialSymList, firstNode); if (connections.Any()) { outerNode = new AnonymousFunctionNode( connections.Select(x => x.Item1), outerNode); foreach (var connection in connections) { outerNode.ConnectInput(connection.Item1, connection.Item2); } } firstNode = outerNode; } nodes[data.Index] = firstNode; } else nodes[data.Index] = new NumberNode(0); } } else { if (partial) { var outerNode = new AnonymousFunctionNode(partialSymList, node); if (connections.Any()) { outerNode = new AnonymousFunctionNode( connections.Select(x => x.Item1), outerNode); foreach (var connection in connections) { node.ConnectInput(connection.Item1, new SymbolNode(connection.Item1)); outerNode.ConnectInput(connection.Item1, connection.Item2); } } node = outerNode; } else { foreach (var connection in connections) { node.ConnectInput(connection.Item1, connection.Item2); } } nodes[outPort] = node; } //If this is a partial application, then remember not to re-eval. if (partial) { OldValue = Value.NewFunction(null); // cache an old value for display to the user RequiresRecalc = false; } preBuilt[this] = nodes; //And we're done return nodes[outPort]; }
/// <summary> /// Save a function. This includes writing to a file and compiling the /// function and saving it to the FSchemeEnvironment /// </summary> /// <param name="definition">The definition to saveo</param> /// <param name="bool">Whether to write the function to file</param> /// <returns>Whether the operation was successful</returns> public void SaveFunction(FunctionDefinition definition, bool writeDefinition = true) { if (definition == null) return; // Get the internal nodes for the function dynWorkspace functionWorkspace = definition.Workspace; // If asked to, write the definition to file if (writeDefinition) { string directory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); string pluginsPath = Path.Combine(directory, "definitions"); try { if (!Directory.Exists(pluginsPath)) Directory.CreateDirectory(pluginsPath); string path = Path.Combine(pluginsPath, FormatFileName(functionWorkspace.Name) + ".dyf"); SaveWorkspace(path, functionWorkspace, definition.FunctionId); } catch (Exception e) { Bench.Log("Error saving:" + e.GetType()); Bench.Log(e); } } try { #region Find outputs // Find output elements for the node IEnumerable<dynNode> outputs = functionWorkspace.Nodes.Where(x => x is dynOutput); var topMost = new List<Tuple<int, dynNode>>(); IEnumerable<string> outputNames; // 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 => x.Inputs[0])); outputNames = outputs.Select(x => (x as dynOutput).Symbol); } else { // if there are no explicitly defined output nodes // get the top most nodes and set THEM as tht output IEnumerable<dynNode> topMostNodes = functionWorkspace.GetTopMostNodes(); var outNames = new List<string>(); foreach (dynNode topNode in topMostNodes) { foreach (int output in Enumerable.Range(0, topNode.OutPortData.Count)) { if (!topNode.HasOutput(output)) { topMost.Add(Tuple.Create(output, topNode)); outNames.Add(topNode.OutPortData[output].NickName); } } } outputNames = outNames; } #endregion // color the node to define its connectivity foreach (var ele in topMost) { ele.Item2.NodeUI.ValidateConnections(); } //Find function entry point, and then compile the function and add it to our environment IEnumerable<dynNode> variables = functionWorkspace.Nodes.Where(x => x is dynSymbol); IEnumerable<string> inputNames = variables.Select(x => (x as dynSymbol).Symbol); INode top; var buildDict = new Dictionary<dynNode, Dictionary<int, INode>>(); if (topMost.Count > 1) { InputNode node = new ExternalFunctionNode( FScheme.Value.NewList, Enumerable.Range(0, topMost.Count).Select(x => x.ToString())); int i = 0; foreach (var topNode in topMost) { string inputName = i.ToString(); node.ConnectInput(inputName, topNode.Item2.Build(buildDict, topNode.Item1)); i++; } top = node; } else top = topMost[0].Item2.BuildExpression(buildDict); // if the node has any outputs, we create a BeginNode in order to evaluate all of them // sequentially (begin evaluates a list of expressions) if (outputs.Any()) { var beginNode = new BeginNode(); List<dynNode> hangingNodes = functionWorkspace.GetTopMostNodes().ToList(); foreach (var tNode in hangingNodes.Select((x, index) => new {Index = index, Node = x})) { beginNode.AddInput(tNode.Index.ToString()); beginNode.ConnectInput(tNode.Index.ToString(), tNode.Node.Build(buildDict, 0)); } beginNode.AddInput(hangingNodes.Count.ToString()); beginNode.ConnectInput(hangingNodes.Count.ToString(), top); top = beginNode; } // make the anonymous function FScheme.Expression expression = Utils.MakeAnon(variables.Select(x => x.NodeUI.GUID.ToString()), top.Compile()); // make it accessible in the FScheme environment FSchemeEnvironment.DefineSymbol(definition.FunctionId.ToString(), expression); //Update existing function nodes which point to this function to match its changes foreach (dynNode el in AllNodes) { if (el is dynFunction) { var node = (dynFunction) el; if (node.Definition != definition) continue; node.SetInputs(inputNames); node.SetOutputs(outputNames); el.NodeUI.RegisterAllPorts(); } } //Call OnSave for all saved elements foreach (dynNode el in functionWorkspace.Nodes) el.onSave(); } catch (Exception ex) { Bench.Log(ex.GetType() + ": " + ex.Message); } }
public void SaveFunction(dynWorkspace functionWorkspace, bool writeDefinition = true) { //Generate xml, and save it in a fixed place if (writeDefinition) { string directory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); string pluginsPath = Path.Combine(directory, "definitions"); try { if (!Directory.Exists(pluginsPath)) Directory.CreateDirectory(pluginsPath); string path = Path.Combine(pluginsPath, FormatFileName(functionWorkspace.Name) + ".dyf"); SaveWorkspace(path, functionWorkspace); } catch (Exception e) { Bench.Log("Error saving:" + e.GetType()); Bench.Log(e); } } try { var outputs = functionWorkspace.Nodes.Where(x => x is dynOutput); var topMost = new List<Tuple<int, dynNode>>(); IEnumerable<string> outputNames; if (outputs.Any()) { topMost.AddRange( outputs.Where(x => x.HasInput(0)).Select(x => x.Inputs[0])); outputNames = outputs.Select(x => (x as dynOutput).Symbol); } else { var topMostNodes = functionWorkspace.GetTopMostNodes(); var outNames = new List<string>(); foreach (var topNode in topMostNodes) { foreach (var output in Enumerable.Range(0, topNode.OutPortData.Count)) { if (!topNode.HasOutput(output)) { topMost.Add(Tuple.Create(output, topNode)); outNames.Add(topNode.OutPortData[output].NickName); } } } outputNames = outNames; } foreach (var ele in topMost) { ele.Item2.NodeUI.ValidateConnections(); } //Find function entry point, and then compile the function and add it to our environment //dynNode top = topMost.FirstOrDefault(); var variables = functionWorkspace.Nodes.Where(x => x is dynSymbol); var inputNames = variables.Select(x => (x as dynSymbol).Symbol); INode top; var buildDict = new Dictionary<dynNode, Dictionary<int, INode>>(); if (topMost.Count > 1) { InputNode node = new ExternalFunctionNode( FScheme.Value.NewList, Enumerable.Range(0, topMost.Count).Select(x => x.ToString())); var i = 0; foreach (var topNode in topMost) { var inputName = i.ToString(); node.ConnectInput(inputName, topNode.Item2.Build(buildDict, topNode.Item1)); i++; } top = node; } else top = topMost[0].Item2.BuildExpression(buildDict); if (outputs.Any()) { var beginNode = new BeginNode(); var hangingNodes = functionWorkspace.GetTopMostNodes().ToList(); foreach (var tNode in hangingNodes.Select((x, index) => new { Index = index, Node = x })) { beginNode.AddInput(tNode.Index.ToString()); beginNode.ConnectInput(tNode.Index.ToString(), tNode.Node.Build(buildDict, 0)); } beginNode.AddInput(hangingNodes.Count.ToString()); beginNode.ConnectInput(hangingNodes.Count.ToString(), top); top = beginNode; } Expression expression = Utils.MakeAnon(variables.Select(x => x.NodeUI.GUID.ToString()), top.Compile()); FSchemeEnvironment.DefineSymbol(functionWorkspace.Name, expression); //Update existing function nodes which point to this function to match its changes foreach (var el in this.AllNodes) { if (el is dynFunction) { var node = (dynFunction)el; if (!node.Symbol.Equals(functionWorkspace.Name)) continue; node.SetInputs(inputNames); node.SetOutputs(outputNames); el.NodeUI.RegisterAllPorts(); } } //Call OnSave for all saved elements foreach (var el in functionWorkspace.Nodes) el.onSave(); //Update new add menu var addItem = (dynFunction)Bench.addMenuItemsDictNew[functionWorkspace.Name].NodeLogic; addItem.SetInputs(inputNames); addItem.SetOutputs(outputNames); addItem.NodeUI.RegisterAllPorts(); addItem.NodeUI.State = ElementState.DEAD; } catch (Exception ex) { Bench.Log(ex.GetType().ToString() + ": " + ex.Message); } }