Example #1
0
        internal void ConvertNodesToCodeInternal(EngineController engineController, INamingProvider namingProvider)
        {
            var selectedNodes = DynamoSelection.Instance
                                               .Selection
                                               .OfType<NodeModel>()
                                               .Where(n => n.IsConvertible);
            if (!selectedNodes.Any())
                return;

            var cliques = NodeToCodeCompiler.GetCliques(selectedNodes).Where(c => !(c.Count == 1 && c.First() is CodeBlockNodeModel));
            var codeBlockNodes = new List<CodeBlockNodeModel>();

            //UndoRedo Action Group----------------------------------------------
            NodeToCodeUndoHelper undoHelper = new NodeToCodeUndoHelper();

            // using (UndoRecorder.BeginActionGroup())
            {
                foreach (var nodeList in cliques)
                {
                    //Create two dictionarys to store the details of the external connections that have to 
                    //be recreated after the conversion
                    var externalInputConnections = new Dictionary<ConnectorModel, string>();
                    var externalOutputConnections = new Dictionary<ConnectorModel, string>();

                    //Also collect the average X and Y co-ordinates of the different nodes
                    int nodeCount = nodeList.Count;

                    var nodeToCodeResult = engineController.ConvertNodesToCode(this.nodes, nodeList, namingProvider);

                    #region Step I. Delete all nodes and their connections

                    double totalX = 0, totalY = 0;

                    foreach (var node in nodeList)
                    {
                        #region Step I.A. Delete the connections for the node

                        foreach (var connector in node.AllConnectors.ToList())
                        {
                            if (!IsInternalNodeToCodeConnection(nodeList, connector))
                            {
                                //If the connector is an external connector, the save its details
                                //for recreation later
                                var startNode = connector.Start.Owner;
                                int index = startNode.OutPorts.IndexOf(connector.Start);
                                //We use the varibleName as the connection between the port of the old Node
                                //to the port of the new node.
                                var variableName = startNode.GetAstIdentifierForOutputIndex(index).Value;

                                //Store the data in the corresponding dictionary
                                if (startNode == node)
                                {
                                    if (nodeToCodeResult.OutputMap.ContainsKey(variableName))
                                        variableName = nodeToCodeResult.OutputMap[variableName];
                                    externalOutputConnections.Add(connector, variableName);
                                }
                                else
                                {
                                    if (nodeToCodeResult.InputMap.ContainsKey(variableName))
                                        variableName = nodeToCodeResult.InputMap[variableName];
                                    externalInputConnections.Add(connector, variableName);
                                }
                            }

                            //Delete the connector
                            undoHelper.RecordDeletion(connector);
                            connector.Delete();
                        }
                        #endregion

                        #region Step I.B. Delete the node
                        totalX += node.X;
                        totalY += node.Y;
                        undoHelper.RecordDeletion(node);
                        RemoveNode(node);
                        #endregion
                    }
                    #endregion

                    #region Step II. Create the new code block node
                    var outputVariables = externalOutputConnections.Values;
                    var newResult = NodeToCodeCompiler.ConstantPropagationForTemp(nodeToCodeResult, outputVariables);

                    // Rewrite the AST using the shortest unique name in case of namespace conflicts
                    NodeToCodeCompiler.ReplaceWithShortestQualifiedName(
                        engineController.LibraryServices.LibraryManagementCore.ClassTable, newResult.AstNodes, ElementResolver);
                    var codegen = new ProtoCore.CodeGenDS(newResult.AstNodes);
                    var code = codegen.GenerateCode();

                    var codeBlockNode = new CodeBlockNodeModel(
                        code,
                        System.Guid.NewGuid(), 
                        totalX / nodeCount,
                        totalY / nodeCount, engineController.LibraryServices, ElementResolver);
                    undoHelper.RecordCreation(codeBlockNode);
                   
                    AddAndRegisterNode(codeBlockNode, false);
                    codeBlockNodes.Add(codeBlockNode);
                    #endregion

                    #region Step III. Recreate the necessary connections
                    var newInputConnectors = ReConnectInputConnections(externalInputConnections, codeBlockNode);
                    foreach (var connector in newInputConnectors)
                    {
                        undoHelper.RecordCreation(connector);
                    }

                    var newOutputConnectors = ReConnectOutputConnections(externalOutputConnections, codeBlockNode);
                    foreach (var connector in newOutputConnectors)
                    {
                        undoHelper.RecordCreation(connector);
                    }
                    #endregion
                }
            }

            undoHelper.ApplyActions(UndoRecorder);

            DynamoSelection.Instance.ClearSelection();
            DynamoSelection.Instance.Selection.AddRange(codeBlockNodes);

            RequestRun();
        }
Example #2
0
 internal NodeToCodeResult ConvertNodesToCode(IEnumerable <NodeModel> graph, IEnumerable <NodeModel> nodes, INamingProvider namingProvider = null)
 {
     return(NodeToCodeCompiler.NodeToCode(libraryServices.LibraryManagementCore, graph, nodes, namingProvider));
 }
Example #3
0
        internal static void ConvertNodesToCodeInternal(this WorkspaceModel workspace, EngineController engineController,
                                                        INamingProvider namingProvider)
        {
            var selectedNodes = DynamoSelection.Instance
                                .Selection
                                .OfType <NodeModel>()
                                .Where(n => n.IsConvertible);

            if (!selectedNodes.Any())
            {
                return;
            }

            var cliques        = NodeToCodeCompiler.GetCliques(selectedNodes).Where(c => !(c.Count == 1 && c.First() is CodeBlockNodeModel));
            var codeBlockNodes = new List <CodeBlockNodeModel>();

            //UndoRedo Action Group----------------------------------------------
            NodeToCodeUndoHelper undoHelper = new NodeToCodeUndoHelper();

            foreach (var nodeList in cliques)
            {
                //Create two dictionarys to store the details of the external connections that have to
                //be recreated after the conversion
                var externalInputConnections  = new Dictionary <ConnectorModel, string>();
                var externalOutputConnections = new Dictionary <ConnectorModel, string>();

                //Also collect the average X and Y co-ordinates of the different nodes
                int nodeCount = nodeList.Count;

                var nodeToCodeResult = engineController.ConvertNodesToCode(workspace.Nodes, nodeList, namingProvider);

                #region Step I. Delete all nodes and their connections

                double totalX = 0, totalY = 0;

                foreach (var node in nodeList)
                {
                    #region Step I.A. Delete the connections for the node

                    foreach (var connector in node.AllConnectors.ToList())
                    {
                        if (!IsInternalNodeToCodeConnection(nodeList, connector))
                        {
                            //If the connector is an external connector, the save its details
                            //for recreation later
                            var startNode = connector.Start.Owner;
                            int index     = startNode.OutPorts.IndexOf(connector.Start);
                            //We use the varibleName as the connection between the port of the old Node
                            //to the port of the new node.
                            var variableName = startNode.GetAstIdentifierForOutputIndex(index).Value;

                            //Store the data in the corresponding dictionary
                            if (startNode == node)
                            {
                                if (nodeToCodeResult.OutputMap.ContainsKey(variableName))
                                {
                                    variableName = nodeToCodeResult.OutputMap[variableName];
                                }
                                externalOutputConnections.Add(connector, variableName);
                            }
                            else
                            {
                                if (nodeToCodeResult.InputMap.ContainsKey(variableName))
                                {
                                    variableName = nodeToCodeResult.InputMap[variableName];
                                }
                                externalInputConnections.Add(connector, variableName);
                            }
                        }

                        //Delete the connector
                        undoHelper.RecordDeletion(connector);
                        connector.Delete();
                    }
                    #endregion

                    #region Step I.B. Delete the node
                    totalX += node.X;
                    totalY += node.Y;
                    undoHelper.RecordDeletion(node);
                    workspace.RemoveAndDisposeNode(node);
                    #endregion
                }
                #endregion

                #region Step II. Create the new code block node
                var outputVariables = externalOutputConnections.Values;
                var newResult       = NodeToCodeCompiler.ConstantPropagationForTemp(nodeToCodeResult, outputVariables);

                // Rewrite the AST using the shortest unique name in case of namespace conflicts
                NodeToCodeCompiler.ReplaceWithShortestQualifiedName(
                    engineController.LibraryServices.LibraryManagementCore.ClassTable, newResult.AstNodes, workspace.ElementResolver);
                var codegen = new ProtoCore.CodeGenDS(newResult.AstNodes);
                var code    = codegen.GenerateCode();

                var codeBlockNode = new CodeBlockNodeModel(
                    code,
                    System.Guid.NewGuid(),
                    totalX / nodeCount,
                    totalY / nodeCount, engineController.LibraryServices, workspace.ElementResolver);
                undoHelper.RecordCreation(codeBlockNode);

                workspace.AddAndRegisterNode(codeBlockNode, false);
                codeBlockNodes.Add(codeBlockNode);
                #endregion

                #region Step III. Recreate the necessary connections
                var newInputConnectors = ReConnectInputConnections(externalInputConnections, codeBlockNode, workspace);
                foreach (var connector in newInputConnectors)
                {
                    undoHelper.RecordCreation(connector);
                }

                var newOutputConnectors = ReConnectOutputConnections(externalOutputConnections, codeBlockNode);
                foreach (var connector in newOutputConnectors)
                {
                    undoHelper.RecordCreation(connector);
                }
                #endregion
            }

            undoHelper.ApplyActions(workspace.UndoRecorder);

            DynamoSelection.Instance.ClearSelection();
            DynamoSelection.Instance.Selection.AddRange(codeBlockNodes);

            Debug.WriteLine(string.Format("Workspace has {0} nodes and {1} connectors after N2C operation.", workspace.Nodes.Count(), workspace.Connectors.Count()));
            workspace.RequestRun();
        }
Example #4
0
 internal NodeToCodeResult ConvertNodesToCode(IEnumerable<NodeModel> graph, IEnumerable<NodeModel> nodes, INamingProvider namingProvider = null)
 {
     return NodeToCodeCompiler.NodeToCode(libraryServices.LibraryManagementCore, graph, nodes, namingProvider);
 }
Example #5
0
 public TypeDependentNameGenetrator(ProtoCore.Core core, INamingProvider namingProvider)
 {
     this.core           = core;
     this.namingProvider = namingProvider;
 }
Example #6
0
        /// <summary>
        /// Compile a set of nodes to ASTs.
        ///
        /// Note:
        /// 1. Nodes should be a clique with regarding to convertibility and
        ///    selection state. That is, these nodes can be safely to be
        ///    converted into a single code block node. It shouldn't have
        ///    unconvertible or unselected node on any path (if there is) that
        ///    connects any two of these nodes, otherwise there will be
        ///    circular references between unconvertible/unselected node and
        ///    code block node.
        ///
        ///    To split arbitary node set into cliques, use
        ///    NodeToCodeUtils.GetCliques().
        ///
        /// 2. WorkspaceNodes are all nodes in current workspace. We need the
        ///    whole graph so that each to-be-converted node will have correct
        ///    order in the final code block node.
        /// </summary>
        /// <param name="core">Library core</param>
        /// <param name="workspaceNodes">The whole workspace nodes</param>
        /// <param name="nodes">Selected node that can be converted to a single code block node</param>
        /// <param name="namingProvider"></param>
        /// <returns></returns>
        internal static NodeToCodeResult NodeToCode(
            ProtoCore.Core core,
            IEnumerable <NodeModel> workspaceNodes,
            IEnumerable <NodeModel> nodes,
            INamingProvider namingProvider)
        {
            // The basic worflow is:
            //   1. Compile each node to get its cde in AST format
            //
            //   2. Variable numbering to avoid confliction. For example, two
            //      code block nodes both have assignment "y = x", we need to
            //      rename "y" to "y1" and "y2" respectively.
            //
            //   3. Variable remapping. For example, code block node
            //      "x = 1" connects to "a = b", where the second code block
            //      node will have initialization "b = x_guid" where "x_guid"
            //      is because of variable mappining in the first code block
            //      node. We should restore it to its original name.
            //
            //      Note in step 2 we may rename "x" to "xn".
            //
            //   4. Generate short name for long name variables. Typically they
            //      are from output ports from other nodes.
            //
            //   5. Do constant progation to optimize the generated code.
            #region Step 1 AST compilation

            AstBuilder builder     = new AstBuilder(null);
            var        sortedGraph = AstBuilder.TopologicalSortForGraph(workspaceNodes);
            var        sortedNodes = sortedGraph.Where(nodes.Contains);
            var        allAstNodes = builder.CompileToAstNodes(sortedNodes, CompilationContext.NodeToCode, false);

            #endregion

            #region Step 2 Varialbe numbering

            // External inputs will be in input map
            // Internal non-cbn will be input map & output map
            // Internal cbn will be in renaming map and output map

            // Map from mapped variable to its original name. These variables
            // are from code block nodes that in the selection.
            Dictionary <string, string> renamingMap = null;;

            // Input variable to renamed input variable map
            Dictionary <string, string> inputMap = null;

            // Output variable to renamed output variable map
            Dictionary <string, string> outputMap = null;

            // Collect type ints for all variables
            Dictionary <string, ProtoCore.Type> typeHints = new Dictionary <string, ProtoCore.Type>();

            // Collect all inputs/outputs/candidate renaming variables
            GetInputOutputMap(nodes, out inputMap, out outputMap, out renamingMap, out typeHints);

            // Variable numbering map. Value field indicates current current
            // numbering value of the variable. For example, there are variables
            // t1, t2, ... tn and the ID of variable t's NumberingState is n.
            var numberingMap = new Dictionary <string, NumberingState>();

            // In this step, we'll renumber all variables that going to be in
            // the same code block node. That is,
            //
            //     "x = 1; y = x;"   and
            //     "x = 2; y = x;"
            //
            // Will be renumbered to
            //
            //    "x1 = 1; y1 = x1;" and
            //    "x2 = 2; y2 = x2;"
            var mappedVariables = new HashSet <string>();
            foreach (var t in allAstNodes)
            {
                // Reset variable numbering map
                foreach (var p in numberingMap)
                {
                    p.Value.IsNewSession = true;
                }

                foreach (var astNode in t.Item2)
                {
                    VariableNumbering(core, astNode, t.Item1, numberingMap, renamingMap, inputMap, outputMap, mappedVariables);
                }
            }

            renamingMap = renamingMap.Where(p => !p.Key.Contains("%"))
                          .ToDictionary(p => p.Key, p => p.Value);
            #endregion

            #region Step 3 Variable remapping
            foreach (var ts in allAstNodes)
            {
                foreach (var astNode in ts.Item2)
                {
                    VariableRemapping(core, astNode, renamingMap, outputMap, mappedVariables);
                }
            }
            #endregion

            #region Step 4 Generate short name
            var nameGenerator = new TypeDependentNameGenetrator(core, namingProvider);

            // temporary variables are double mapped.
            foreach (var key in outputMap.Keys.ToList())
            {
                if (key.StartsWith(Constants.kTempVarForNonAssignment) &&
                    outputMap[key].StartsWith(Constants.kTempVarForNonAssignment))
                {
                    var shortName = GetNextShortName(nameGenerator, typeHints, mappedVariables, key);
                    var tempVar   = outputMap[key];
                    outputMap[key]     = shortName;
                    outputMap[tempVar] = shortName;

                    mappedVariables.Add(shortName);
                }
            }

            foreach (var ts in allAstNodes)
            {
                foreach (var astNode in ts.Item2)
                {
                    ShortNameMapping(core, astNode, inputMap, nameGenerator, mappedVariables, typeHints);
                    foreach (var kvp in inputMap)
                    {
                        if (kvp.Value != String.Empty && outputMap.ContainsKey(kvp.Key))
                        {
                            outputMap[kvp.Key] = kvp.Value;
                        }
                    }
                    ShortNameMapping(core, astNode, outputMap, nameGenerator, mappedVariables, typeHints);
                }
            }
            #endregion

            var result = new NodeToCodeResult(allAstNodes.SelectMany(x => x.Item2), inputMap, outputMap);
            return(result);
        }