Exemple #1
0
        /// <summary>
        /// Map variable to shorter name.
        /// </summary>
        /// <param name="astNode"></param>
        /// <param name="shortNameMap"></param>
        /// <param name="nameGenerator"></param>
        private static void ShortNameMapping(
            ProtoCore.Core core,
            AssociativeNode astNode,
            Dictionary <string, string> shortNameMap,
            ShortNameGenerator nameGenerator,
            HashSet <string> mappedVariables)
        {
            Action <IdentifierNode> func = n =>
            {
                string shortName;
                if (shortNameMap.TryGetValue(n.Value, out shortName))
                {
                    if (shortName == string.Empty)
                    {
                        shortName = nameGenerator.GetNextName();
                        while (mappedVariables.Contains(shortName))
                        {
                            shortName = nameGenerator.GetNextName();
                        }

                        shortNameMap[n.Value] = shortName;
                    }
                    n.Value = n.Name = shortName;
                }
            };

            IdentifierVisitor visitor = new IdentifierVisitor(func, core);

            astNode.Accept(visitor);
        }
Exemple #2
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="astBuilder">Ast builder</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>
        /// <returns></returns>
        public static NodeToCodeResult NodeToCode(
            ProtoCore.Core core,
            AstBuilder astBuilder,
            IEnumerable <NodeModel> workspaceNodes,
            IEnumerable <NodeModel> nodes)
        {
            // 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

            var sortedGraph = AstBuilder.TopologicalSortForGraph(workspaceNodes);
            var sortedNodes = sortedGraph.Where(nodes.Contains);

            var allAstNodes = astBuilder.CompileToAstNodes(sortedNodes, AstBuilder.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 all inputs/outputs/candidate renaming variables
            GetInputOutputMap(nodes, out inputMap, out outputMap, out renamingMap);

            // 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 ShortNameGenerator();

            // temporary variables are double mapped.
            foreach (var key in outputMap.Keys.ToList())
            {
                if (key.StartsWith(Constants.kTempVarForNonAssignment) &&
                    outputMap[key].StartsWith(Constants.kTempVarForNonAssignment))
                {
                    string shortName = nameGenerator.GetNextName();
                    while (mappedVariables.Contains(shortName))
                    {
                        shortName = nameGenerator.GetNextName();
                    }

                    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);
                    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);
                }
            }
            #endregion

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