private void CompileToAstNodes(NodeModel node, List<AssociativeNode> resultList, CompilationContext context, bool verboseLogging) { var inputAstNodes = new List<AssociativeNode>(); var inPortsCount = node.InPorts.Count; var inPortDataCount = node.InPortData.Count; //TODO: inputsCount should be removed in future. // InPortData won't be used anymore, so we shouldn't take into account InPortData.Count. int inputsCount = inPortsCount > inPortDataCount ? inPortsCount : inPortDataCount; for (int index = 0; index < inputsCount; index++) { Tuple<int, NodeModel> inputTuple; if (node.TryGetInput(index, out inputTuple)) { int outputIndexOfInput = inputTuple.Item1; NodeModel inputModel = inputTuple.Item2; AssociativeNode inputNode = inputModel.GetAstIdentifierForOutputIndex(outputIndexOfInput); #if DEBUG Validity.Assert(inputNode != null, "Shouldn't have null nodes in the AST list"); #endif inputAstNodes.Add(inputNode); } else { if (node.InPorts.Count > index) { var port = node.InPorts[index]; if (port.UsingDefaultValue && port.DefaultValueEnabled) { inputAstNodes.Add(port.DefaultValue); } else { inputAstNodes.Add(new NullNode()); } } else { Log("Node does not have InPortData at the requested index."); } } } //TODO: This should do something more than just log a generic message. --SJE if (node.State == ElementState.Error) Log("Error in Node. Not sent for building and compiling"); if (context == CompilationContext.DeltaExecution || context == CompilationContext.PreviewGraph) OnAstNodeBuilding(node.GUID); #if DEBUG Validity.Assert(inputAstNodes.All(n => n != null), "Shouldn't have null nodes in the AST list"); #endif var scopedNode = node as ScopedNodeModel; IEnumerable<AssociativeNode> astNodes = scopedNode != null ? scopedNode.BuildAstInScope(inputAstNodes, verboseLogging, this) : node.BuildAst(inputAstNodes, context); if (verboseLogging) { foreach (var n in astNodes) { Log(n.ToString()); } } if(null == astNodes) resultList.AddRange(new AssociativeNode[0]); else if (context == CompilationContext.DeltaExecution || context == CompilationContext.PreviewGraph) { OnAstNodeBuilt(node.GUID, astNodes); resultList.AddRange(astNodes); } else if (context == CompilationContext.NodeToCode) { resultList.AddRange(astNodes); } else //Inside custom node compilation. { bool notified = false; foreach (var item in astNodes) { if (item is FunctionDefinitionNode) { if (!notified) OnAstNodeBuilding(node.GUID); notified = true; //Register the function node in global scope with Graph Sync data, //so that we don't have a function definition inside the function def //of custom node. OnAstNodeBuilt(node.GUID, new[] { item }); } else resultList.Add(item); } } }
private void _CompileToAstNodes(NodeModel node, List<AssociativeNode> resultList, bool isDeltaExecution) { var inputAstNodes = new List<AssociativeNode>(); foreach (int index in Enumerable.Range(0, node.InPortData.Count)) { Tuple<int, NodeModel> inputTuple; if (node.TryGetInput(index, out inputTuple)) { int outputIndexOfInput = inputTuple.Item1; NodeModel inputModel = inputTuple.Item2; AssociativeNode inputNode = inputModel.GetAstIdentifierForOutputIndex(outputIndexOfInput); #if DEBUG Validity.Assert(inputNode != null, "Shouldn't have null nodes in the AST list"); #endif inputAstNodes.Add(inputNode); } else { PortData port = node.InPortData[index]; inputAstNodes.Add( port.HasDefaultValue ? AstFactory.BuildPrimitiveNodeFromObject(port.DefaultValue) : new NullNode()); } } //TODO: This should do something more than just log a generic message. --SJE if (node.State == ElementState.Error) dynSettings.DynamoLogger.Log("Error in Node. Not sent for building and compiling"); if (isDeltaExecution) OnAstNodeBuilding(node.GUID); #if DEBUG Validity.Assert(!inputAstNodes.Any((n) => n == null), "Shouldn't have null nodes in the AST list"); #endif IEnumerable<AssociativeNode> astNodes = node.BuildAst(inputAstNodes); if (dynSettings.Controller.DebugSettings.VerboseLogging) { foreach (var n in astNodes) { dynSettings.DynamoLogger.Log(n.ToString()); } } if(null == astNodes) resultList.AddRange(new AssociativeNode[0]); else if (isDeltaExecution) { OnAstNodeBuilt(node.GUID, astNodes); resultList.AddRange(astNodes); } else //Inside custom node compilation. { bool notified = false; foreach (var item in astNodes) { if (item is FunctionDefinitionNode) { if (!notified) OnAstNodeBuilding(node.GUID); notified = true; //Register the function node in global scope with Graph Sync data, //so that we don't have a function definition inside the function def //of custom node. OnAstNodeBuilt(node.GUID, new AssociativeNode[] { item }); } else resultList.Add(item); } } }
/// <summary> /// Starts from the input node as root, do breadth-first and post-order /// traversal of the graph (inputs nodes as children nodes). Breadth-first /// traversal ensures all inputs nodes are visited in their input order /// and post-order traversal ensures all upstream nodes are visited /// firstly. /// </summary> /// <param name="node">Root node</param> /// <param name="nodeFlags">Dictionary to record if a node has been visited or not</param> /// <param name="sortedNodes">Record all visited nodes</param> private static void BfsTraverse( NodeModel node, Dictionary<NodeModel, MarkFlag> nodeFlags, Queue<NodeModel> sortedNodes) { MarkFlag flag; if (!nodeFlags.TryGetValue(node, out flag)) { flag = MarkFlag.NoMark; nodeFlags[node] = flag; } if (flag != MarkFlag.NoMark) return; nodeFlags[node] = MarkFlag.TempMark; for (int i = 0; i < node.InPortData.Count; ++i) { Tuple<int, NodeModel> t; if (!node.TryGetInput(i, out t)) continue; BfsTraverse(t.Item2, nodeFlags, sortedNodes); } sortedNodes.Enqueue(node); nodeFlags[node] = MarkFlag.Marked; }