示例#1
0
        /// <summary>
        /// Gets the type instance for the specified symbol.
        /// </summary>
        /// <param name="parentType">The user type from which this symbol comes from (examples: field type, template type...).</param>
        /// <param name="symbol">The original type.</param>
        /// <param name="bitLength">Number of bits used for this symbol.</param>
        internal virtual TypeInstance GetSymbolTypeInstance(UserType parentType, Symbol symbol, int bitLength = 0)
        {
            switch (symbol.Tag)
            {
            case CodeTypeTag.BuiltinType:
                if (bitLength == 1)
                {
                    return(new BasicTypeInstance(CodeNaming, typeof(bool)));
                }
                switch (symbol.BasicType)
                {
                case BasicType.Bit:
                case BasicType.Bool:
                    return(new BasicTypeInstance(CodeNaming, typeof(bool)));

                case BasicType.Char:
                case BasicType.WChar:
                case BasicType.Char16:
                case BasicType.Char32:
                    return(new BasicTypeInstance(CodeNaming, typeof(char)));

                case BasicType.BSTR:
                    return(new BasicTypeInstance(CodeNaming, typeof(string)));

                case BasicType.Void:
                case BasicType.NoType:
                    return(new BasicTypeInstance(CodeNaming, typeof(VoidType)));

                case BasicType.Float:
                    return(new BasicTypeInstance(CodeNaming, symbol.Size <= 4 ? typeof(float) : typeof(double)));

                case BasicType.Int:
                case BasicType.Long:
                    switch (symbol.Size)
                    {
                    case 0:
                        return(new BasicTypeInstance(CodeNaming, typeof(VoidType)));

                    case 1:
                        return(new BasicTypeInstance(CodeNaming, typeof(sbyte)));

                    case 2:
                        return(new BasicTypeInstance(CodeNaming, typeof(short)));

                    case 4:
                        return(new BasicTypeInstance(CodeNaming, typeof(int)));

                    case 8:
                        return(new BasicTypeInstance(CodeNaming, typeof(long)));

                    default:
                        throw new Exception($"Unexpected type length {symbol.Size}");
                    }

                case BasicType.UInt:
                case BasicType.ULong:
                    switch (symbol.Size)
                    {
                    case 0:
                        return(new BasicTypeInstance(CodeNaming, typeof(VoidType)));

                    case 1:
                        return(new BasicTypeInstance(CodeNaming, typeof(byte)));

                    case 2:
                        return(new BasicTypeInstance(CodeNaming, typeof(ushort)));

                    case 4:
                        return(new BasicTypeInstance(CodeNaming, typeof(uint)));

                    case 8:
                        return(new BasicTypeInstance(CodeNaming, typeof(ulong)));

                    default:
                        throw new Exception($"Unexpected type length {symbol.Size}");
                    }

                case BasicType.Hresult:
                    return(new BasicTypeInstance(CodeNaming, typeof(uint)));        // TODO: Create Hresult type

                default:
                    throw new Exception($"Unexpected basic type {symbol.BasicType}");
                }

            case CodeTypeTag.Pointer:
            {
                Symbol   pointerType = symbol.ElementType;
                UserType pointerUserType;

                // When exporting pointer from Global Modules, always export types as code pointer.
                if (parentType is GlobalsUserType && GetUserType(pointerType, out pointerUserType))
                {
                    return(new PointerTypeInstance(UserTypeInstance.Create(pointerUserType, this)));
                }

                TypeInstance innerType = GetSymbolTypeInstance(parentType, pointerType);

                if (innerType is TemplateArgumentTypeInstance)
                {
                    return(new PointerTypeInstance(innerType));
                }
                switch (pointerType.Tag)
                {
                case CodeTypeTag.BuiltinType:
                case CodeTypeTag.Enum:
                {
                    if ((innerType as BasicTypeInstance)?.BasicType == typeof(VoidType))
                    {
                        return(new BasicTypeInstance(CodeNaming, typeof(NakedPointer)));
                    }
                    return(new PointerTypeInstance(innerType));
                }

                case CodeTypeTag.Class:
                case CodeTypeTag.Structure:
                case CodeTypeTag.Union:
                    return(innerType);

                default:
                    return(new PointerTypeInstance(innerType));
                }
            }

            case CodeTypeTag.Enum:
            case CodeTypeTag.Class:
            case CodeTypeTag.Structure:
            case CodeTypeTag.Union:
            case CodeTypeTag.TemplateArgumentConstant:
            {
                // Try to apply transformation on the type
                UserTypeTransformation transformation = FindTransformation(symbol, parentType);

                if (transformation != null)
                {
                    return(new TransformationTypeInstance(CodeNaming, transformation));
                }

                // Try to find user type that represents current type
                UserType userType;

                if (GetUserType(symbol, out userType))
                {
                    TypeInstance         type         = UserTypeInstance.Create(userType, this);
                    TemplateTypeInstance genericsTree = type as TemplateTypeInstance;

                    if (genericsTree != null && !genericsTree.CanInstantiate)
                    {
                        return(new VariableTypeInstance(CodeNaming));
                    }
                    return(type);
                }

                // We were unable to find user type. If it is enum, use its basic type
                if (symbol.Tag == CodeTypeTag.Enum)
                {
                    return(new BasicTypeInstance(CodeNaming, EnumUserType.GetEnumBasicType(symbol)));
                }

                // Is it template argument constant?
                if (symbol.Tag == CodeTypeTag.TemplateArgumentConstant && symbol.UserType is TemplateArgumentConstantUserType constantArgument)
                {
                    return(new TemplateArgumentConstantTypeInstance(constantArgument));
                }

                // Fall-back to Variable
                return(new VariableTypeInstance(CodeNaming));
            }

            case CodeTypeTag.Array:
                return(new ArrayTypeInstance(GetSymbolTypeInstance(parentType, symbol.ElementType)));

            case CodeTypeTag.Function:
                return(new FunctionTypeInstance(CodeNaming));

            case CodeTypeTag.BaseClass:
            {
                symbol = symbol.Module.GetSymbol(symbol.Name);
                return(GetSymbolTypeInstance(parentType, symbol, bitLength));
            }

            default:
                throw new Exception("Unexpected type tag " + symbol.Tag);
            }
        }
示例#2
0
 /// <summary>
 /// Look up for user type based on the specified module and type string.
 /// </summary>
 /// <param name="module">The module.</param>
 /// <param name="typeString">The type string.</param>
 /// <param name="userType">The found user type.</param>
 /// <returns><c>true</c> if user type was found.</returns>
 internal virtual bool GetUserType(SymbolProviders.Module module, string typeString, out UserType userType)
 {
     userType = GlobalCache.GetUserType(typeString, module);
     return(userType != null);
 }
示例#3
0
        /// <summary>
        /// Adds template symbols to user type factory and generates template user types.
        /// </summary>
        /// <param name="symbols">The template symbols grouped around the same template type.</param>
        /// <param name="nameSpace">The namespace.</param>
        /// <param name="generationFlags">The user type generation flags.</param>
        /// <returns>Generated user types for the specified symbols.</returns>
        internal IEnumerable <UserType> AddTemplateSymbols(IEnumerable <Symbol> symbols, string nameSpace, UserTypeGenerationFlags generationFlags)
        {
            // Bucketize template user types based on number of template arguments
            var buckets = new Dictionary <int, List <SpecializedTemplateUserType> >();

            foreach (Symbol symbol in symbols)
            {
                UserType userType = null;

                // We want to ignore "empty" generic classes (for now)
                if (symbol.Name == null || symbol.Size == 0)
                {
                    continue;
                }

                // Generate template user type
                SpecializedTemplateUserType templateType = new SpecializedTemplateUserType(symbol, null, nameSpace, this);

                if (!templateType.WronglyFormed)
                {
                    List <SpecializedTemplateUserType> templates;

                    symbol.UserType = templateType;
                    if (!buckets.TryGetValue(templateType.AllTemplateArguments.Count, out templates))
                    {
                        buckets.Add(templateType.AllTemplateArguments.Count, templates = new List <SpecializedTemplateUserType>());
                    }
                    templates.Add(templateType);
                }

                if (userType != null)
                {
                    yield return(userType);
                }
            }

            // Add newly generated types
            foreach (List <SpecializedTemplateUserType> templatesInBucket in buckets.Values)
            {
                // TODO: Verify that all templates in the list can be described by the same class (also do check for inner-types)

                // Sort Templates by Class Name.
                // This removes ambiguity caused by parallel type processing.
                //
                List <SpecializedTemplateUserType> templates = templatesInBucket.OrderBy(t => t.Symbol.Name.Count(c => c == '*'))
                                                               .ThenBy(t => t.Symbol.Name.Count(c => c == '<'))
                                                               .ThenBy(t => t.Symbol.Name).ToList();

                // Select best suited type for template
                SpecializedTemplateUserType template = templates.First();
                int bestScore = int.MaxValue;

                foreach (var specializedTemplate in templates)
                {
                    var arguments = specializedTemplate.AllTemplateArguments;
                    int score     = 0;

                    for (int i = 0; i < arguments.Count; i++)
                    {
                        var argument = arguments[i];

                        // Check if this is repeated type
                        bool repeated = false;

                        for (int j = 0; j < i && !repeated; j++)
                        {
                            repeated = argument == arguments[j];
                        }
                        if (repeated)
                        {
                            score += 100;
                        }

                        // Check if argument is constant
                        if (argument.Tag == CodeTypeTag.TemplateArgumentConstant)
                        {
                            continue;
                        }

                        // Check if argument is simple user type
                        if ((argument.Tag == CodeTypeTag.Class || argument.Tag == CodeTypeTag.Structure || argument.Tag == CodeTypeTag.Union || argument.Tag == CodeTypeTag.Enum) && !argument.Name.Contains("<"))
                        {
                            score += 1;
                            continue;
                        }

                        // Check if argments is function
                        if (argument.Tag == CodeTypeTag.Function)
                        {
                            score += 2;
                            continue;
                        }

                        // Check if argument is template
                        if (argument.Name.Contains("<"))
                        {
                            score += 20;
                            continue;
                        }

                        // All others fall into the same category
                        score += 5;
                    }

                    // Check if this is the best one
                    if (score < bestScore)
                    {
                        bestScore = score;
                        template  = specializedTemplate;
                    }
                }

                yield return(new TemplateUserType(template, templates, this));
            }
        }
示例#4
0
        /// <summary>
        /// Post process the types:
        ///  - If UserType has static members in more than one module, split it into multiple user types.
        ///  - Find parent type/namespace.
        /// </summary>
        /// <param name="userTypes">The list of user types.</param>
        /// <param name="symbolNamespaces">The symbol namespaces.</param>
        /// <param name="commonNamespace">The namespace name for types found in multiple modules.</param>
        /// <returns>Newly generated user types.</returns>
        internal IEnumerable <UserType> ProcessTypes(IEnumerable <UserType> userTypes, Dictionary <Symbol, string> symbolNamespaces, string commonNamespace)
        {
            List <UserType> newTypes = new List <UserType>();

            // Collect all constants used by template types
            Dictionary <string, Symbol> constantsDictionary = new Dictionary <string, Symbol>();

            foreach (TemplateUserType templateType in userTypes.OfType <TemplateUserType>())
            {
                foreach (SpecializedTemplateUserType specialization in templateType.Specializations)
                {
                    foreach (Symbol symbol in specialization.AllTemplateArguments)
                    {
                        if (symbol.Tag != CodeTypeTag.TemplateArgumentConstant)
                        {
                            continue;
                        }
                        if (!constantsDictionary.ContainsKey(symbol.Name))
                        {
                            constantsDictionary.Add(symbol.Name, symbol);
                        }
                    }
                }
            }

            // Create user types for template type constants
            if (constantsDictionary.Count > 0)
            {
                // Create namespace that will contain all constants (TemplateConstants)
                NamespaceUserType templateConstants = new NamespaceUserType(new[] { "TemplateConstants" }, commonNamespace, this);

                newTypes.Add(templateConstants);

                // Foreach constant, create new user type
                foreach (Symbol symbol in constantsDictionary.Values)
                {
                    symbol.UserType = new TemplateArgumentConstantUserType(symbol, this);
                    symbol.UserType.UpdateDeclaredInType(templateConstants);
                    newTypes.Add(symbol.UserType);
                }
            }

            // Assign generated user types to template type constant arguments
            foreach (TemplateUserType templateType in userTypes.OfType <TemplateUserType>())
            {
                foreach (SpecializedTemplateUserType specialization in templateType.Specializations)
                {
                    foreach (Symbol symbol in specialization.AllTemplateArguments)
                    {
                        if (symbol.Tag != CodeTypeTag.TemplateArgumentConstant || symbol.UserType != null)
                        {
                            continue;
                        }
                        symbol.UserType = constantsDictionary[symbol.Name].UserType;
                    }
                }
            }

            // Split user types that have static members in more than one module
            List <UserType> staticUserTypes = new List <UserType>();
            Dictionary <Symbol, UserType> staticUserTypesBySymbol = new Dictionary <Symbol, UserType>();

            foreach (UserType userType in userTypes)
            {
                if (userType.DontExportStaticFields)
                {
                    continue;
                }

                List <Symbol> symbols = GlobalCache.GetSymbolStaticFieldsSymbols(userType.Symbol);

                if (symbols == null || symbols.Count <= 1)
                {
                    continue;
                }

                bool foundSameNamespace = false;

                foreach (var symbol in symbols)
                {
                    string nameSpace = symbol.Module.Namespace;

                    if (userType.Namespace != nameSpace)
                    {
                        UserType staticUserType = new UserType(symbol, null, nameSpace, this)
                        {
                            ExportOnlyStaticFields = true
                        };
                        staticUserTypes.Add(staticUserType);
                        staticUserTypesBySymbol.Add(symbol, staticUserType);
                    }
                    else
                    {
                        foundSameNamespace = true;
                    }
                }

                if (!foundSameNamespace)
                {
                    userType.DontExportStaticFields = true;
                }
            }
            newTypes.AddRange(staticUserTypes);

            // TODO: This needs to happen before template types creation. We need to verify that all types declared in template type are matched correctly.
            // Find parent type/namespace
            Dictionary <string, Dictionary <string, UserType> > namespaceTypesByModuleNamespace = new Dictionary <string, Dictionary <string, UserType> >();
            Action <UserType> findParentType = (UserType userType) =>
            {
                Symbol        symbol     = userType.Symbol;
                string        symbolName = symbol.Name;
                List <string> namespaces = symbol.Namespaces;

                if (namespaces.Count == 1)
                {
                    // Class is not defined in namespace nor in type.
                    return;
                }

                Dictionary <string, UserType> namespaceTypes;
                string notNullUserTypeNamespace = userType.Namespace ?? string.Empty;

                if (!namespaceTypesByModuleNamespace.TryGetValue(notNullUserTypeNamespace, out namespaceTypes))
                {
                    namespaceTypesByModuleNamespace.Add(notNullUserTypeNamespace, namespaceTypes = new Dictionary <string, UserType>());
                }

                StringBuilder currentNamespaceSB        = new StringBuilder();
                UserType      previousNamespaceUserType = null;

                for (int i = 0; i < namespaces.Count - 1; i++)
                {
                    if (i > 0)
                    {
                        currentNamespaceSB.Append("::");
                    }
                    currentNamespaceSB.Append(namespaces[i]);

                    string   currentNamespace = currentNamespaceSB.ToString();
                    UserType namespaceUserType;

                    if (!namespaceTypes.TryGetValue(currentNamespace, out namespaceUserType))
                    {
                        namespaceUserType = GlobalCache.GetUserType(currentNamespace, symbol.Module);
                        if (namespaceUserType != null && userType.Namespace != namespaceUserType.Namespace)
                        {
                            staticUserTypesBySymbol.TryGetValue(symbol.Module.GetSymbol(currentNamespace), out namespaceUserType);
                        }
                        if (namespaceUserType != null && userType.Namespace != namespaceUserType.Namespace)
                        {
                            namespaceUserType = null;
                        }
                    }

                    if (namespaceUserType == null)
                    {
                        namespaceUserType = new NamespaceUserType(new string[] { namespaces[i] }, previousNamespaceUserType == null ? userType.Namespace : null, this);
                        if (previousNamespaceUserType != null)
                        {
                            namespaceUserType.UpdateDeclaredInType(previousNamespaceUserType);
                        }
                        namespaceTypes.Add(currentNamespace, namespaceUserType);
                        newTypes.Add(namespaceUserType);
                    }

                    previousNamespaceUserType = namespaceUserType;
                }

                userType.UpdateDeclaredInType(previousNamespaceUserType);
            };

            foreach (UserType userType in userTypes.Concat(staticUserTypes))
            {
                Symbol symbol = userType.Symbol;

                if (symbol.Tag != CodeTypeTag.Class && symbol.Tag != CodeTypeTag.Structure && symbol.Tag != CodeTypeTag.Union && symbol.Tag != CodeTypeTag.Enum)
                {
                    continue;
                }

                if (userType is TemplateUserType templateType)
                {
                    foreach (SpecializedTemplateUserType specializedType in templateType.Specializations)
                    {
                        findParentType(specializedType);
                    }
                    templateType.UpdateDeclaredInType(templateType.SpecializedRepresentative.DeclaredInType);

                    // TODO: Once we fix how we pick specialized representative this won't be needed. Specialized representative needs to have all inner types.
                    if (templateType.SpecializedRepresentative.DeclaredInType is TemplateUserType t)
                    {
                        templateType.UpdateDeclaredInType(t);
                    }
                    if (templateType.SpecializedRepresentative.DeclaredInType is SpecializedTemplateUserType t2)
                    {
                        templateType.UpdateDeclaredInType(t2.TemplateType.SpecializedRepresentative);
                    }
                }
                else
                {
                    findParentType(userType);
                }
            }

            // Update Class Name if it has duplicate with the namespace it is declared in
            foreach (UserType userType in newTypes.Concat(userTypes))
            {
                if (userType.DeclaredInType != null && userType.TypeName == userType.DeclaredInType.TypeName)
                {
                    // Since changing user type name can generate duplicate name, we need to adjust name to be unique.
                    int counter = 0;

                    do
                    {
                        if (counter > 0)
                        {
                            userType.UpdateConstructorNameSuffix($"_{counter}");
                        }
                        else
                        {
                            userType.UpdateConstructorNameSuffix("_");
                        }
                        counter++;
                    }while (userType.DeclaredInType.InnerTypes.Where(t => t != userType).Any(t => t.TypeName == userType.TypeName));
                }
            }

            // Find all derived classes
            foreach (UserType userType in userTypes)
            {
                // We are doing this only for UDTs
                if (userType is EnumUserType || userType is GlobalsUserType || userType is NamespaceUserType)
                {
                    continue;
                }

                // For template user types, we want to remember all specializations
                TemplateUserType templateUserType = userType as TemplateUserType;

                if (templateUserType != null)
                {
                    foreach (SpecializedTemplateUserType specializedUserType in templateUserType.Specializations)
                    {
                        AddDerivedClassToBaseClasses(specializedUserType);
                    }
                }
                else
                {
                    AddDerivedClassToBaseClasses(userType);
                }
            }

            // Merge namespaces when possible
            foreach (UserType userType in newTypes)
            {
                NamespaceUserType nameSpace = userType as NamespaceUserType;

                if (nameSpace == null)
                {
                    continue;
                }

                nameSpace.MergeIfPossible();
            }

            // Remove empty namespaces after merge
            List <UserType> removedUserTypes = new List <UserType>();

            foreach (UserType userType in newTypes)
            {
                NamespaceUserType nameSpace = userType as NamespaceUserType;

                if (nameSpace == null)
                {
                    continue;
                }

                if (nameSpace.InnerTypes.Count == 0)
                {
                    removedUserTypes.Add(nameSpace);
                }
            }

            return(newTypes.Except(removedUserTypes));
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="UserTypeTransformation"/> class.
 /// </summary>
 /// <param name="transformation">The XML transformation definition.</param>
 /// <param name="typeConverter">The type converter.</param>
 /// <param name="ownerUserType">The owner user type.</param>
 /// <param name="type">The type that should be transformed to user type.</param>
 public UserTypeTransformation(XmlTypeTransformation transformation, Func <string, string> typeConverter, UserType ownerUserType, Symbol type)
 {
     Transformation     = transformation;
     this.typeConverter = typeConverter;
     this.ownerUserType = ownerUserType;
     this.type          = type;
     typeStringCache    = SimpleCache.CreateStruct(() => Transformation.TransformType(type.Name, typeConverter));
 }