Example #1
0
        private static EnumMemberDeclarationSyntax BuildEnumMember(CppEnumItem cppEnumItem, int prefixLength)
        {
            return(EnumMemberDeclaration(PrettyItemName(cppEnumItem.Name))
                   .WithEqualsValue(EqualsValueClause(LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal((int)cppEnumItem.Value))))
                   .WithAdditionalAnnotations(new SyntaxAnnotation(Annotations.NativeName, cppEnumItem.Name)));

            string PrettyItemName(string itemName)
            {
                var parts = itemName[prefixLength..].Split("_", StringSplitOptions.RemoveEmptyEntries);
                var name  = string.Concat(parts.Select(p => p[..1].ToUpperInvariant() + p[1..]));
Example #2
0
        public static CSharpElement ConvertEnumItem(CSharpConverter converter, CppEnumItem cppEnumItem, CSharpElement context)
        {
            // If the context is not an enum, we don't support this scenario.
            if (!(context is CSharpEnum csEnum))
            {
                return(null);
            }

            var enumItemName = converter.GetCSharpName(cppEnumItem, context);
            var csEnumItem   = new CSharpEnumItem(enumItemName)
            {
                CppElement = cppEnumItem
            };

            csEnum.Members.Add(csEnumItem);
            csEnumItem.Comment = converter.GetCSharpComment(cppEnumItem, context);

            // Process any enum item value expression (e.g ENUM_ITEM = 1 << 2)
            if (cppEnumItem.ValueExpression != null)
            {
                var integerValue = converter.ConvertExpression(cppEnumItem.ValueExpression);

                csEnumItem.Value = $"unchecked(({csEnum.IntegerBaseType}){(string.IsNullOrEmpty(integerValue) ? cppEnumItem.Value + "" : integerValue)})";

                // Tag the enum has flags
                if (!csEnum.IsFlags && csEnumItem.Value.Contains("<<"))
                {
                    csEnum.IsFlags = true;
                }

                if (csEnum.IsFlags)
                {
                    csEnumItem.Value = csEnumItem.Value.Replace("<<", $" << ({csEnum.IntegerBaseType})");
                }
            }

            if (converter.Options.GenerateEnumItemAsFields && context.Parent is CSharpClass csClass)
            {
                var csEnumItemAsField = new CSharpField(enumItemName)
                {
                    Modifiers = CSharpModifiers.Const,
                    FieldType = csEnum,
                    Comment   = csEnumItem.Comment,
                    InitValue = $"{csEnum.Name}.{csEnumItem.Name}"
                };
                converter.ApplyDefaultVisibility(csEnumItemAsField, csClass);

                csClass.Members.Add(csEnumItemAsField);
            }

            return(csEnumItem);
        }
Example #3
0
 /// <summary>
 /// Renames the specified C++ enum item.
 /// </summary>
 /// <param name="cppEnumItem">The C++ enum item.</param>
 /// <param name="rootEnumName">Name of the root C++ enum.</param>
 /// <returns>The C# name of this enum item</returns>
 public string Rename(CppEnumItem cppEnumItem, string rootEnumName) =>
 UnKeyword(RenameCore(cppEnumItem, rootEnumName));
Example #4
0
 /// <summary>
 /// Renames the specified C++ enum item.
 /// </summary>
 /// <param name="cppEnumItem">The C++ enum item.</param>
 /// <param name="rootEnumName">Name of the root C++ enum.</param>
 /// <returns>The C# name of this enum item</returns>
 public string Rename(CppEnumItem cppEnumItem, string rootEnumName)
 {
     return(RecordRename(cppEnumItem, UnKeyword(RenameCore(cppEnumItem, rootEnumName))));
 }
Example #5
0
        public static void ProcessFile(string inputFile, string outputPath, string outputFile, string defaultNamespace, string defaultClass)
        {
            inputFile = Path.GetFullPath(inputFile);

            Console.WriteLine($"Processing file '{Path.GetFileName(inputFile)}'...");

            //Writing
            var converterOptions = new CSharpConverterOptions()
            {
                DefaultNamespace                 = defaultNamespace,
                DefaultClassLib                  = defaultClass,
                DefaultOutputFilePath            = outputFile,
                DefaultDllImportNameAndArguments = "Library",
                DispatchOutputPerInclude         = false,
                GenerateEnumItemAsFields         = false,
                TypedefCodeGenKind               = CppTypedefCodeGenKind.NoWrap,

                MappingRules =
                {
                    //Remove prefixes from elements' names.
                    e => e.MapAll <CppElement>().CppAction((converter,                                                        element) => {
                        if (element is ICppMember member)
                        {
                            string prefix = member switch {
                                CppType _ => "IPL",
                                CppEnumItem _ => "IPL_",
                                _ => null
                            };

                            if (prefix != null)
                            {
                                member.Name = StringUtils.Capitalize(StringUtils.RemovePrefix(member.Name,                    prefix));
                            }
                        }
                    }).CSharpAction((converter,                                                                               element) => {
                        if (element is CSharpMethod method)
                        {
                            const string Prefix = "ipl";

                            string oldName = method.Name;
                            string newName = StringUtils.Capitalize(StringUtils.RemovePrefix(oldName,                         Prefix));

                            //Add an EntryPoint parameter to the DllImportAttribute, so that this rename doesn't break anything.
                            if (method.Attributes.FirstOrDefault(attrib => attrib is CSharpDllImportAttribute) is CSharpDllImportAttribute dllImportAttribute)
                            {
                                dllImportAttribute.EntryPoint = $@"""{oldName}""";
                            }

                            method.Name = newName;
                        }
                    }),

                    //Replace the bool enum with an actual bool.
                    e => e.Map <CppEnum>("Bool").Discard(),
                    e => e.MapAll <CppDeclaration>().CSharpAction((converter,                                                 element) => {
                        CSharpType type;
                        Action <CSharpType> setType;

                        if (element is CSharpField field)
                        {
                            type    = field.FieldType;
                            setType = value => field.FieldType = value;
                        }
                        else if (element is CSharpParameter parameter)
                        {
                            type    = parameter.ParameterType;
                            setType = value => parameter.ParameterType = value;
                        }
                        else
                        {
                            return;
                        }

                        if (type is CSharpFreeType freeType && freeType.Text == "unsupported_type /* enum Bool {...} */")
                        {
                            var boolean = converter.GetCSharpType(CppPrimitiveType.Bool,                                      element);

                            setType(boolean);

                            if (boolean is CSharpTypeWithAttributes typeWithAttributes)
                            {
                                foreach (CSharpMarshalAttribute attribute in typeWithAttributes.Attributes.Where(a => a is CSharpMarshalAttribute))
                                {
                                    attribute.UnmanagedType = CSharpUnmanagedKind.U4;
                                }
                            }
                        }
                    }),

                    //Rename enum elements from SCREAMING_SNAKECASE to LameupperCamelcase. There are manual fixes below, for cases where words aren't separated.
                    e => e.MapAll <CppEnumItem>().CppAction((converter,                                                       element) => {
                        var enumItem = (CppEnumItem)element;

                        string name     = enumItem.Name;
                        string[] splits = name.Split('_');

                        if (splits.Length > 1)
                        {
                            string prefix = splits[0];

                            //Remove (potentially partial) prefixes of enum's name on its items' names.
                            if (name.Length > prefix.Length + 1 && name.StartsWith(prefix,                                    StringComparison.InvariantCultureIgnoreCase))
                            {
                                name   = name.Substring(prefix.Length + 1);
                                splits = name.Split('_');
                            }

                            //Capitalize each part
                            for (int i = 0; i < splits.Length; i++)
                            {
                                string split = splits[i];
                                char[] chars = split.ToCharArray();

                                for (int j = 0; j < chars.Length; j++)
                                {
                                    chars[j] = j == 0 ? char.ToUpper(chars[j]) : char.ToLower(chars[j]);
                                }

                                splits[i] = new string(chars);
                            }

                            name = string.Join(string.Empty,                                                                  splits);
                        }

                        enumItem.Name = name;
                    }),

                    //Fix weird 'ref void' parameters.
                    e => e.MapAll <CppParameter>().CSharpAction((converter,                                                   element) => {
                        var parameter     = (CSharpParameter)element;
                        var parameterType = parameter.ParameterType;

                        if (parameterType is CSharpRefType refType && refType.ElementType is CSharpPrimitiveType primitiveType && primitiveType.Kind == CSharpPrimitiveKind.Void)
                        {
                            parameter.ParameterType = CSharpPrimitiveType.IntPtr;
                        }
                    }),

                    //Turn some 'ref' parameters to 'out' or 'in' based on \param documentation.
                    e => e.MapAll <CppParameter>().CSharpAction((converter,                                                   element) => {
                        var parameter = (CSharpParameter)element;

                        if (!(parameter.ParameterType is CSharpRefType refParameterType))
                        {
                            return;
                        }

                        if (!(element.Parent is CSharpMethod method) || !(method.CppElement is CppFunction function))
                        {
                            return;
                        }

                        if (!(function.Comment?.Children?.FirstOrDefault(c => c is CppCommentParamCommand pc && pc.ParamName == parameter.Name) is CppCommentParamCommand parameterComment))
                        {
                            return;
                        }

                        if (!(parameterComment?.Children?.FirstOrDefault() is CppCommentParagraph paragraph))
                        {
                            return;
                        }

                        string paragraphText = paragraph.ToString().Trim();

                        if (paragraphText.StartsWith("[out]"))
                        {
                            refParameterType.Kind = CSharpRefKind.Out;
                        }
                        else if (paragraphText.StartsWith("[in]"))                            //Never actually used
                        {
                            refParameterType.Kind = CSharpRefKind.In;
                        }
                    }),

                    //Turn a 2D fixed array into an 1D one.
                    e => e.Map <CppField>("Matrix4x4::elements").Type("float",                                       16),

                    //Manually fix casing on some enum properties. This could theoretically be made automatic through crazy dictionary-based algorithms, but that's overkill.
                    e => e.Map <CppEnumItem>("Error::Outofmemory").Name("OutOfMemory"),
                    e => e.Map <CppEnumItem>("SceneType::Radeonrays").Name("RadeonRays"),
                    e => e.Map <CppEnumItem>("ConvolutionType::Trueaudionext").Name("TrueAudioNext"),
                    e => e.Map <CppEnumItem>("ChannelLayout::Fivepointone").Name("FivePointOne"),
                    e => e.Map <CppEnumItem>("ChannelLayout::Sevenpointone").Name("SevenPointOne"),
                    e => e.Map <CppEnumItem>("AmbisonicsOrdering::Fursemalham").Name("FurseMalham"),
                    e => e.Map <CppEnumItem>("AmbisonicsNormalization::Fursemalham").Name("FurseMalham"),
                    e => e.Map <CppEnumItem>("AmbisonicsNormalization::Sn3d").Name("SN3D"),
                    e => e.Map <CppEnumItem>("AmbisonicsNormalization::N3d").Name("N3D"),
                    e => e.Map <CppEnumItem>("DistanceAttenuationModelType::Inversedistance").Name("InversedDistance"),
                    e => e.Map <CppEnumItem>("DirectOcclusionMode::Notransmission").Name("NoTransmission"),
                    e => e.Map <CppEnumItem>("DirectOcclusionMode::Transmissionbyvolume").Name("TransmissionByVolume"),
                    e => e.Map <CppEnumItem>("DirectOcclusionMode::Transmissionbyfrequency").Name("TransmissionByFrequency"),
                    e => e.Map <CppEnumItem>("BakedDataType::Staticsource").Name("StaticSource"),
                    e => e.Map <CppEnumItem>("BakedDataType::Staticlistener").Name("StaticListener"),
                    e => e.Map <CppEnumItem>("BakedDataType::Uniformfloor").Name("UniformFloor"),
                }
            };

            converterOptions.IncludeFolders.Add(Path.GetDirectoryName(inputFile));

            var compilation = CSharpConverter.Convert(new List <string> {
                inputFile
            }, converterOptions);

            if (compilation.HasErrors)
            {
                foreach (var message in compilation.Diagnostics.Messages)
                {
                    if (message.Type == CppLogMessageType.Error)
                    {
                        Console.WriteLine(message);
                    }
                }

                Console.ReadKey();

                return;
            }

            using var fileSystem    = new PhysicalFileSystem();
            using var subFileSystem = new SubFileSystem(fileSystem, fileSystem.ConvertPathFromInternal(outputPath));

            var codeWriterOptions = new CodeWriterOptions(subFileSystem);
            var codeWriter        = new CodeWriter(codeWriterOptions);

            compilation.DumpTo(codeWriter);
        }
Example #6
0
 public CsEnumItem(CppEnumItem cppElement, string name, string value) : base(cppElement, name)
 {
     Value = value;
 }
Example #7
0
 public override bool VisitCppEnumItem(CppEnumItem cppEnumItem)
 {
     return(base.VisitCppEnumItem(cppEnumItem));
 }