Exemple #1
0
        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;
                });
        }
Exemple #2
0
        //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];
        }
Exemple #3
0
        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);
        }
Exemple #8
0
        //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);
            }
        }