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; }); }
private Dictionary<int, INode> buildPartialSingleOut(IEnumerable<string> portNames, List<Tuple<string, INode>> connections, List<string> partials) { InputNode node = Compile(portNames); foreach (var partial in partials) { node.ConnectInput(partial, new SymbolNode(partial)); } var outerNode = new AnonymousFunctionNode(partials, 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); } } return new Dictionary<int, INode> { { 0, outerNode } }; }
//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]; }