// Returns a set of namespaces referenced by the given namespace.
        // A namespace is referenced if any type in the given namespace has a property which
        // references a type in another namespace.
        public static List <IRNamespace> ResolveNSReferences(IRNamespace ns)
        {
            HashSet <IRNamespace> references = new HashSet <IRNamespace>();

            // Only classes make references.
            foreach (var irClass in ns.Classes)
            {
                // Loop each property and record the referenced namespace.
                foreach (var prop in irClass.Properties)
                {
                    if (prop.Type == PropertyTypeKind.TYPE_REF)
                    {
                        // Go up in the parent chain to find the containing namespace!
                        var parent = prop.ReferencedType.Parent;
                        // A non-set parent could wreak havoc here..
                        while (!(parent is IRNamespace))
                        {
                            parent = parent.Parent;
                        }
                        // Parent should be a namespace instance by now
                        references.Add((parent as IRNamespace));
                    }
                }
            }

            // Remove reference to our own file.
            references.Remove(ns);
            return(references.ToList());
        }
Exemple #2
0
        // The list of types start and end with the same type!
        private void ResolveCircularNS(List <IRNamespace> circle)
        {
            if (circle.Count() > 3)
            {
                throw new Exception("This method is not created for solving big circular dependancies!");
            }

            // Suppose there are ONLY DIRECT CIRCULAR DEPENDANCIES.
            // This means one type points to another which points to the first!
            var nsOne = circle[0];
            var nsTwo = circle[1];

            // Decide which namespace is not allowed to point to the other.
            var cmpNS = CompareNSHeights(nsOne, nsTwo);
            // Namespaces indicating where types will be moved towards.
            // By default, nsOne is the target; nsTwo the source.
            IRNamespace source = nsTwo;
            IRNamespace target = nsOne;

            if (cmpNS == 1)
            {
                // The compare function says otherwise, so swap source/target.
                source = nsOne;
                target = nsTwo;
            }

            // Select all types that need to be moved from source.
            var typesToMove = GetAllReferencingClasses(source, target);

            // Move these types to target.
            foreach (var type in typesToMove)
            {
                MoveType(type, source, target);
            }
        }
        private void RenameNamespace(IRNamespace ns)
        {
            Program.Log.Info("Renaming namespace `{0}`", ns.OriginalName);

            // Use the original name to generate a hash
            // and append it to the namespace.
            var nsHash = GetMD5Hash(ns.OriginalName);
            // Generate affix
            var affix = string.Format("_{0}", nsHash.Substring(0, 3));

            // Append affix to both shortname and fullname.
            ns.ShortName = ns.ShortName + affix;
            ns.FullName  = ns.FullName + affix;

            // Update all the types of this namespace.
            foreach (var irClass in ns.Classes)
            {
                irClass.UpdateTypeName(ns);
            }

            foreach (var irEnum in ns.Enums)
            {
                irEnum.UpdateTypeName(ns);
            }
        }
        // Returns the namespace object for the given object.
        public static IRNamespace GetNamespaceForType(IRTypeNode type,
                                                      out List <IRProgramNode> parentChain)
        {
            // Keep track of the path towards the parent namespace.
            parentChain = new List <IRProgramNode>();
            IRNamespace result = null;

            // Recursively call all parents until namespace is reached
            var p = type.Parent;

            while (p != null)
            {
                // Add p as parent.
                parentChain.Add(p);

                if (p is IRNamespace)
                {
                    result = p as IRNamespace;
                    break;
                }

                p = p.Parent;
            }

            // Reverse chain so that it starts with the namespace.
            // The last element in the list is the direct parent of the type.
            parentChain.Reverse();

            return(result);
        }
        private void ResolveCircularTypes(List <IRTypeNode> circle)
        {
            // All unique types within the given list are moved together into a seperate
            // namespace, because that's the only way to solve these kind of circular dependancies.
            // This list will NEVER contain enums!
            IEnumerable <IRClass> distincttypes = circle.Distinct().Cast <IRClass>();

            // TODO: Better naming algorithm?! (Longest commong substring)
            // The longest substring between the fullnames of each type's namespace.
            var    allTypeNamespaceNames = circle.Select(type => _TypeNSMapper[type].FullName).ToList();
            string newNSName             = DependancyUtil.LongestmatchingSubstring(allTypeNamespaceNames).Trim('.');
            // Also construct a shortname from the new namespace fullname
            string newNSShortName = newNSName.Substring(newNSName.LastIndexOf('.') + 1);

            // NOTE; A suffix is appended here in order to not increase the degree count
            // for the subject namespace (vertex).
            // Pulling types into a seperate namespace helps flattening the graph into a spanning,
            // while the alternative would increase the length of circular namespace chains.
            newNSName      += EXTRACTED_NS_SUFFIX;
            newNSShortName += EXTRACTED_NS_SUFFIX;

            // There still might already be a namespace with that name, so a test is necessary anyway!
            IRNamespace newNS = _program.GetCreateNamespace(newNSName);

            // And copy over all types to this namespace.
            foreach (IRClass irClass in distincttypes)
            {
                IRNamespace oldNS = _TypeNSMapper[irClass];
                MoveType(irClass, oldNS, newNS);
            }

            // No need to add the namespace to the program anymore!
        }
        public static List <IRNamespace> FindNSParents(IRProgram program, IRNamespace subject)
        {
            // Return all namespaces whos fullname are found at the beginnen of the subject
            // namespace.
            var subjName = subject.FullName;
            var parents  = program.Namespaces.Where(p => subjName.StartsWith(p.FullName)).ToList();

            // Remove subject, because fullname matches always with itself.
            parents.Remove(subject);
            return(parents);
        }
Exemple #7
0
        // Write out all set options onto the given textstream.
        protected void WriteFileOptions(IRNamespace ns, string fileName, TextWriter w)
        {
            // Loop each option and write to the TextWriter.
            foreach (var kv in _fileOptions)
            {
                var optValue = kv.Value(ns, fileName);
                var option   = string.Format("option {0} = \"{1}\";", kv.Key, optValue);

                w.WriteLine(option);
            }
        }
Exemple #8
0
        // Function almost identical to TypeTopologicalVisit(..)
        private void NSTopologicalVisit(IRNamespace node, List <IRNamespace> topologicalOrder,
                                        Dictionary <IRNamespace, NODE_STATE> nodeState, List <IRNamespace> visitedNodes)
        {
            // Each type is represented as a NODE.
            // NODE STATES:
            //  - ALIVE: Node needs to be processed.
            //  - UNDEAD: Currently processing this node.
            //  - DEAD: This node has been succesfully visited.

            NODE_STATE state = nodeState[node];

            if (state == NODE_STATE.DEAD)
            {
                return;
            }

            visitedNodes.Add(node);

            if (state == NODE_STATE.UNDEAD)
            {
                // Create a list of all nodes within our circle.
                var circleEntryIDx = visitedNodes.IndexOf(node);
                // Do not switch into 0-based indexing, because we want a list beginning and ending
                // with the same node!
                var circleLength = visitedNodes.Count() - circleEntryIDx;
                var circle       = visitedNodes.GetRange(circleEntryIDx, circleLength);

                throw new CircularException <IRNamespace>(circle);
            }

            // Node is ALIVE and will be processed.
            nodeState[node] = NODE_STATE.UNDEAD;
            // Find all dependancies of the current namespace.
            var dependancies = _NSDependancies[node];

            // Visit each namespace dependancy.
            foreach (var dep in dependancies)
            {
                // Send a copy of visited nodes to not litter the list of circular dependant nodes
                // when we reach an undead node.
                NSTopologicalVisit(dep, topologicalOrder, nodeState, visitedNodes.ToList());
            }

            // Node is recursively visited.
            nodeState[node] = NODE_STATE.DEAD;
            topologicalOrder.Add(node);
        }
        // Solves name collisions between types in one namespace.
        private void SolveCollisionsWithin(IRNamespace ns, List <string> allShortNames)
        {
            // Find all types which collide.
            var collisions = allShortNames.GroupBy(x => x)
                             .Where(group => group.Count() > 1)
                             .Select(group => group.Key);

            foreach (var collisionName in collisions)
            {
                // Find all types matching the collision name.
                // NO case mismatch!
                var classesEnumeration = ns.Classes.Where(c => c.ShortName.Equals(collisionName));
                var enumEnumeration    = ns.Enums.Where(e => e.ShortName.Equals(collisionName));

                // Throw them together in one list.
                List <IRTypeNode> collidedTypes = new List <IRTypeNode>();
                collidedTypes.AddRange(classesEnumeration);
                collidedTypes.AddRange(enumEnumeration);

                // Rename collided types.
                RenameTypes(collidedTypes);
            }
        }
 // Converts a namespace to a package string.
 // The package string is based on the location of the actual file.
 // The package string equals the (relative) path to the folder containing files that
 // share the same package as parent.
 // eg: pkg_parent.pkg_child => <rel path>/pkg_parent/pkg_child/some_file.proto
 public static string ResolvePackageName(IRNamespace ns)
 {
     return(ns.FullName.ToLower());
 }
        // Converts data from internal caches into the IR Program structure.
        public override IRProgram GetRoot()
        {
            // Create a list of all types to process.
            List <TypeDefinition> classesToProcess = new List <TypeDefinition>(_classCache.Keys);
            List <TypeDefinition> enumsToProcess   = new List <TypeDefinition>(_enumCache.Keys);

            // Holds a set of all known namespaces.
            Dictionary <string, IRNamespace> nsSet = new Dictionary <string, IRNamespace>();

            // Until all types are processed, we repeat the same operation.
            while (classesToProcess.Count() > 0)
            {
                // Take the first item from the list.
                var currentType = classesToProcess.ElementAt(0);
                classesToProcess.RemoveAt(0);
                // Find namespace list.
                var         nsName = GetNamespaceName(currentType);
                IRNamespace ns;
                nsSet.TryGetValue(nsName, out ns);
                if (ns == null)
                {
                    // Construct a shortname of the last namespace part of the full name.
                    var lastDotIdx  = nsName.LastIndexOf('.');
                    var nsShortname = (lastDotIdx != -1) ? nsName.Substring(lastDotIdx + 1) : nsName;
                    ns = new IRNamespace(nsName, nsShortname)
                    {
                        Classes = new List <IRClass>(),
                        Enums   = new List <IREnum>(),
                    };
                    nsSet[nsName] = ns;
                }

                // Get the matching IR object.
                var irClass = _classCache[currentType];
                if (irClass.IsPrivate != true && irClass.Parent == null)
                {
                    irClass.Parent = ns;
                }
                // Save it into the namespace.
                ns.Classes.Add(irClass);
            }

            // Do basically the same for enums.
            while (enumsToProcess.Count() > 0)
            {
                // Take the first item from the list.
                var currentType = enumsToProcess.ElementAt(0);
                enumsToProcess.RemoveAt(0);
                // Find namespace list.
                var         nsName = GetNamespaceName(currentType);
                IRNamespace ns;
                nsSet.TryGetValue(nsName, out ns);
                if (ns == null)
                {
                    // Construct a shortname of the last namespace part of the full name.
                    var lastDotIdx  = nsName.LastIndexOf('.');
                    var nsShortname = (lastDotIdx != -1) ? nsName.Substring(lastDotIdx + 1) : nsName;
                    ns = new IRNamespace(nsName, nsShortname)
                    {
                        Classes = new List <IRClass>(),
                        Enums   = new List <IREnum>(),
                    };
                    nsSet[nsName] = ns;
                }

                // Get the matching IR object.
                var irEnum = _enumCache[currentType];
                if (irEnum.IsPrivate != true && irEnum.Parent == null)
                {
                    irEnum.Parent = ns;
                }
                // Save it into the namespace.
                ns.Enums.Add(irEnum);
            }

            // Generate IR root of all namespaces.
            _root = new IRProgram()
            {
                Namespaces = nsSet.Values.ToList(),
            };
            // Return the program root.
            return(_root);
        }