public void Basic() { var config = new ConfigFile { Id = nameof(Basic), Namespace = nameof(Basic), Includes = { new IncludeRule { Attach = true, File = "cppEnum.h", Namespace = nameof(Basic) } } }; var cppModel = new CppModule("SharpGenTestModule"); var cppInclude = new CppInclude("cppEnum"); var cppEnum = new CppEnum("TestEnum"); cppEnum.AddEnumItem("Element1", "0"); cppEnum.AddEnumItem("Element2", "1"); cppInclude.Add(cppEnum); cppModel.Add(cppInclude); var(solution, _) = MapModel(cppModel, config); var members = solution.EnumerateDescendants(); Assert.Single(members.OfType <CsEnum>()); var csEnum = members.OfType <CsEnum>().First(); Assert.Single(csEnum.EnumItems.Where(item => item.Name == "Element1" && item.Value == "0")); Assert.Single(csEnum.EnumItems.Where(item => item.Name == "Element2" && item.Value == "1")); Assert.Equal(TypeRegistry.Int32, csEnum.UnderlyingType); }
public void Enum() { var config = new ConfigFile { Id = nameof(Enum), Namespace = nameof(Enum), Includes = { new IncludeRule { Attach = true, File = "cppEnum.h", Namespace = nameof(Enum) } }, Mappings = { new RemoveRule { Enum = @".*ToRemove\d+" } } }; var cppModel = new CppModule("SharpGenTestModule"); var cppInclude = new CppInclude("cppEnum"); var cppEnum = new CppEnum("TestEnum"); cppInclude.Add(cppEnum); cppInclude.Add(new CppEnum("EnumToRemove1")); cppModel.Add(cppInclude); var(solution, _) = MapModel(cppModel, config); var members = solution.EnumerateDescendants(); Assert.Single(members.OfType <CsEnum>()); }
/// <summary> /// Parses the specified C++ header file and fills the <see cref="CppModule"/> with defined macros. /// </summary> /// <param name="file">The C++ header file to parse.</param> /// <param name="group">The CppIncludse object to fill with macro definitions.</param> public void Parse(string file, CppModule group) { _gccxml.Preprocess(file, ParseLine); foreach (var includeName in _mapIncludeToMacros.Keys) { var includeId = Path.GetFileNameWithoutExtension(includeName).ToLower(); var include = group.FindInclude(includeId); if (include == null) { include = new CppInclude() { Name = includeId }; group.Add(include); } foreach (var macroDefinition in _mapIncludeToMacros[includeName]) { include.Add(new CppDefine(macroDefinition.Key, macroDefinition.Value)); } } }
public void ExplicitUnderlyingType(string underlyingType) { var config = new ConfigFile { Id = nameof(ExplicitUnderlyingType), Namespace = nameof(ExplicitUnderlyingType), Includes = { new IncludeRule { Attach = true, File = "cppEnum.h", Namespace = nameof(ExplicitUnderlyingType) } } }; var cppModel = new CppModule("SharpGenTestModule"); var cppInclude = new CppInclude("cppEnum"); var cppEnum = new CppEnum("TestEnum") { UnderlyingType = underlyingType }; cppInclude.Add(cppEnum); cppModel.Add(cppInclude); var(solution, _) = MapModel(cppModel, config); Assert.Single(solution.EnumerateDescendants().OfType <CsEnum>()); var csEnum = solution.EnumerateDescendants().OfType <CsEnum>().First(); Assert.Equal(TypeRegistry.ImportPrimitiveType(underlyingType), csEnum.UnderlyingType); }
public void NonPortableStructAlignmentRaisesError() { var config = new ConfigFile { Id = nameof(NonPortableStructAlignmentRaisesError), Namespace = nameof(NonPortableStructAlignmentRaisesError), Includes = { new IncludeRule { File = "test.h", Attach = true, Namespace = nameof(NonPortableStructAlignmentRaisesError) } }, Bindings = { new BindRule("int", "System.Int32") } }; var structure = new CppStruct("Test"); structure.Add(new CppField("bitfield1") { TypeName = "int", IsBitField = true, BitOffset = 16, Offset = 0, }); structure.Add(new CppField("bitfield2") { TypeName = "int", IsBitField = true, BitOffset = 16, Offset = 0 }); structure.Add(new CppField("pointer") { TypeName = "int", Pointer = "*", Offset = 1 }); structure.Add(new CppField("field") { TypeName = "int", Offset = 2, }); var include = new CppInclude("test"); include.Add(structure); var module = new CppModule("SharpGenTestModule"); module.Add(include); using (LoggerMessageCountEnvironment(1, LogLevel.Error)) using (LoggerCodeRequiredEnvironment(LoggingCodes.NonPortableAlignment)) { MapModel(module, config); } }
public void MultipleBitfieldOffsetsGeneratedCorrectly() { var config = new ConfigFile { Id = nameof(MultipleBitfieldOffsetsGeneratedCorrectly), Namespace = nameof(MultipleBitfieldOffsetsGeneratedCorrectly), Includes = { new IncludeRule { File = "test.h", Attach = true, Namespace = nameof(MultipleBitfieldOffsetsGeneratedCorrectly) } }, Bindings = { new BindRule("int", "System.Int32") } }; var structure = new CppStruct("Test"); structure.Add(new CppField("bitfield1") { TypeName = "int", IsBitField = true, BitOffset = 16, Offset = 0, }); structure.Add(new CppField("field") { TypeName = "int", Offset = 1, }); structure.Add(new CppField("bitfield2") { TypeName = "int", IsBitField = true, BitOffset = 16, Offset = 2 }); var include = new CppInclude("test"); include.Add(structure); var module = new CppModule("SharpGenTestModule"); module.Add(include); var(solution, _) = MapModel(module, config); var csStruct = solution.EnumerateDescendants().OfType <CsStruct>().First(); var bitField1 = csStruct.Fields.First(field => field.Name == "Bitfield1"); Assert.Equal(0, bitField1.BitOffset); Assert.Equal(0u, bitField1.Offset); Assert.Equal((1 << 16) - 1, bitField1.BitMask); Assert.True(bitField1.IsBitField); var csField = csStruct.Fields.First(field => field.Name == "Field"); Assert.Equal(4u, csField.Offset); Assert.False(csField.IsBitField); var bitField2 = csStruct.Fields.First(field => field.Name == "Bitfield2"); Assert.Equal(0, bitField2.BitOffset); Assert.Equal(8u, bitField2.Offset); Assert.Equal((1 << 16) - 1, bitField2.BitMask); Assert.True(bitField2.IsBitField); }
public void PointerSizeReturnValueNotLarge() { var config = new ConfigFile { Id = nameof(PointerSizeReturnValueNotLarge), Namespace = nameof(PointerSizeReturnValueNotLarge), Includes = { new IncludeRule { File = "pointerSize.h", Attach = true, Namespace = nameof(PointerSizeReturnValueNotLarge) } }, Extension = { new DefineExtensionRule { Struct = "SharpGen.Runtime.PointerSize", SizeOf = 8, IsNativePrimitive = true, } }, Bindings = { new BindRule("int", "SharpGen.Runtime.PointerSize") } }; var iface = new CppInterface { Name = "Interface", TotalMethodCount = 1 }; iface.Add(new CppMethod { Name = "method", ReturnValue = new CppReturnValue { TypeName = "int" } }); var include = new CppInclude { Name = "pointerSize" }; include.Add(iface); var module = new CppModule(); module.Add(include); var(solution, _) = MapModel(module, config); Assert.Single(solution.EnumerateDescendants().OfType <CsInterface>()); var csIface = solution.EnumerateDescendants().OfType <CsInterface>().First(); Assert.Single(csIface.Methods); var method = csIface.Methods.First(); Assert.False(method.IsReturnStructLarge); }
/// <summary> /// Get include path for cpp include /// </summary> private string GetIncludePathOfCppInclude(ConfigMapping configurationContext, CppInclude unit) { IncludeMapping includeOfUnit = null; IEnumerable <ConfigMapping> configFilesLoaded = configurationContext.ConfigFilesLoaded; foreach (ConfigMapping configFileLoad in configFilesLoaded) { foreach (IncludeMapping include in configFileLoad.Includes) { if (include.Id == unit.Name) { includeOfUnit = include; break; } } if (includeOfUnit != null) { break; } } return((includeOfUnit != null) ? includeOfUnit.File : "invalid"); }
public void Basic() { var config = new ConfigFile { Id = nameof(Basic), Namespace = nameof(Basic), Includes = { new IncludeRule { Attach = true, File = "func.h", Namespace = nameof(Basic) } }, Extension = { new CreateExtensionRule { NewClass = $"{nameof(Basic)}.Functions", } }, Bindings = { new BindRule("int", "System.Int32") }, Mappings = { new MappingRule { Function = "Test", FunctionDllName = "\"Test.dll\"", Group = $"{nameof(Basic)}.Functions" } } }; var function = new CppFunction("Test") { ReturnValue = new CppReturnValue { TypeName = "int", } }; var include = new CppInclude("func"); var module = new CppModule("SharpGenTestModule"); include.Add(function); module.Add(include); var(solution, _) = MapModel(module, config); Assert.Single(solution.EnumerateDescendants <CsGroup>()); var group = solution.EnumerateDescendants <CsGroup>().First(); Assert.Equal("Functions", group.Name); Assert.Single(group.Functions); var csFunc = group.Functions.First(); Assert.Equal(TypeRegistry.Int32, csFunc.ReturnValue.PublicType); Assert.Empty(csFunc.Parameters); Assert.Equal(Visibility.Static, csFunc.Visibility & Visibility.Static); }
public void DefineWithNativeImplementationDefinesNativeImplementationType() { var config = new ConfigFile { Id = nameof(Simple), Namespace = nameof(Simple), Includes = { new IncludeRule { File = "interface.h", Attach = true, Namespace = nameof(Simple) } }, Extension = { new DefineExtensionRule { Interface = "Imported.Param", NativeImplementation = "Imported.ParamNative" } }, Bindings = { new BindRule("int", "System.Int32"), new BindRule("Param", "Imported.Param") } }; var iface = new CppInterface { Name = "Interface", TotalMethodCount = 1 }; var method = new CppMethod { Name = "method", ReturnValue = new CppReturnValue { TypeName = "int" } }; method.Add(new CppParameter { Name = "param", TypeName = "Param", Pointer = "*" }); iface.Add(method); var include = new CppInclude { Name = "interface" }; include.Add(iface); var module = new CppModule(); module.Add(include); var(solution, _) = MapModel(module, config); Assert.Single(solution.EnumerateDescendants().OfType <CsParameter>()); var param = solution.EnumerateDescendants().OfType <CsParameter>().First(); Assert.IsType <CsInterface>(param.PublicType); Assert.NotNull(((CsInterface)param.PublicType).NativeImplementation); Assert.False(Logger.HasErrors); }
public void NonPortableStructAlignmentRaisesError() { var config = new Config.ConfigFile { Id = nameof(NonPortableStructAlignmentRaisesError), Namespace = nameof(NonPortableStructAlignmentRaisesError), Includes = { new Config.IncludeRule { File = "test.h", Attach = true, Namespace = nameof(NonPortableStructAlignmentRaisesError) } }, Bindings = { new Config.BindRule("int", "System.Int32") } }; var structure = new CppStruct { Name = "Test" }; structure.Add(new CppField { Name = "bitfield1", TypeName = "int", IsBitField = true, BitOffset = 16, Offset = 0, }); structure.Add(new CppField { Name = "bitfield2", TypeName = "int", IsBitField = true, BitOffset = 16, Offset = 0 }); structure.Add(new CppField { Name = "pointer", TypeName = "int", Pointer = "*", Offset = 1 }); structure.Add(new CppField { Name = "field", TypeName = "int", Offset = 2, }); var include = new CppInclude { Name = "test" }; include.Add(structure); var module = new CppModule(); module.Add(include); var(solution, _) = MapModel(module, config); AssertLoggingCodeLogged(LoggingCodes.NonPortableAlignment); }
public void UnionsWithPointersGeneratesStructure() { var config = new Config.ConfigFile { Id = nameof(UnionsWithPointersGeneratesStructure), Namespace = nameof(UnionsWithPointersGeneratesStructure), Includes = { new Config.IncludeRule { File = "test.h", Attach = true, Namespace = nameof(UnionsWithPointersGeneratesStructure) } }, Bindings = { new Config.BindRule("int", "System.Int32") } }; var structure = new CppStruct { Name = "Test", IsUnion = true }; structure.Add(new CppField { Name = "pointer", TypeName = "int", Pointer = "*" }); structure.Add(new CppField { Name = "scalar", TypeName = "int" }); var include = new CppInclude { Name = "test" }; include.Add(structure); var module = new CppModule(); module.Add(include); var(solution, _) = MapModel(module, config); var csStruct = solution.EnumerateDescendants().OfType <CsStruct>().First(); foreach (var field in csStruct.Fields) { Assert.Equal(0, field.Offset); } Assert.False(Logger.HasErrors); }
public void IntFieldMappedToBoolIsMarkedAsBoolToInt() { var structName = "BoolToInt"; var config = new Config.ConfigFile { Id = nameof(IntFieldMappedToBoolIsMarkedAsBoolToInt), Namespace = nameof(IntFieldMappedToBoolIsMarkedAsBoolToInt), Includes = { new Config.IncludeRule { File = "test.h", Attach = true, Namespace = nameof(IntFieldMappedToBoolIsMarkedAsBoolToInt) } }, Bindings = { new Config.BindRule("int", "System.Int32"), new Config.BindRule("bool", "System.Boolean") }, Mappings = { new Config.MappingRule { Field = $"{structName}::field", MappingType = "bool", }, } }; var structure = new CppStruct { Name = structName }; structure.Add(new CppField { Name = "field", TypeName = "int" }); var include = new CppInclude { Name = "test" }; include.Add(structure); var module = new CppModule(); module.Add(include); var(solution, _) = MapModel(module, config); Assert.Single(solution.EnumerateDescendants().OfType <CsStruct>().Where(csStruct => csStruct.Name == structName)); var generatedStruct = solution.EnumerateDescendants().OfType <CsStruct>().First(csStruct => csStruct.Name == structName); Assert.Single(generatedStruct.Fields); var field = generatedStruct.Fields.First(); Assert.True(field.IsBoolToInt); }
public void InheritingStructs() { var config = new Config.ConfigFile { Id = nameof(InheritingStructs), Namespace = nameof(InheritingStructs), Includes = { new Config.IncludeRule { File = "struct.h", Attach = true, Namespace = nameof(SequentialOffsets) } }, Bindings = { new Config.BindRule("int", "System.Int32") } }; var baseStruct = new CppStruct { Name = "base" }; baseStruct.Add(new CppField { Name = "field", TypeName = "int" }); var inheritingStruct = new CppStruct { Name = "inheriting", Base = "base" }; inheritingStruct.Add(new CppField { Name = "field2", TypeName = "int", Offset = 1 }); var cppInclude = new CppInclude { Name = "struct" }; var cppModule = new CppModule(); cppModule.Add(cppInclude); cppInclude.Add(baseStruct); cppInclude.Add(inheritingStruct); var(solution, _) = MapModel(cppModule, config); var csStruct = solution.EnumerateDescendants().OfType <CsStruct>().First(@struct => @struct.Name == "Inheriting"); var field = csStruct.Fields.First(fld => fld.Name == "Field"); var field2 = csStruct.Fields.First(fld => fld.Name == "Field2"); Assert.Equal(0, field.Offset); Assert.Equal(4, field2.Offset); }
public void NonPortableLayoutDoesNotErrorWhenMarkedForCustomMarshalling() { var config = new ConfigFile { Id = nameof(NonPortableLayoutDoesNotErrorWhenMarkedForCustomMarshalling), Namespace = nameof(NonPortableLayoutDoesNotErrorWhenMarkedForCustomMarshalling), Includes = { new IncludeRule { File = "test.h", Attach = true, Namespace = nameof(NonPortableLayoutDoesNotErrorWhenMarkedForCustomMarshalling) } }, Bindings = { new BindRule("int", "System.Int32") }, Mappings = { new MappingRule { Struct = "Test", StructCustomMarshal = true } } }; var structure = new CppStruct("Test"); structure.Add(new CppField("bitfield1") { TypeName = "int", IsBitField = true, BitOffset = 16, Offset = 0, }); structure.Add(new CppField("bitfield2") { TypeName = "int", IsBitField = true, BitOffset = 16, Offset = 0 }); structure.Add(new CppField("pointer") { TypeName = "int", Pointer = "*", Offset = 1 }); structure.Add(new CppField("field") { TypeName = "int", Offset = 2, }); var include = new CppInclude("test"); include.Add(structure); var module = new CppModule("SharpGenTestModule"); module.Add(include); var(solution, _) = MapModel(module, config); Assert.False(Logger.HasErrors); }
public void Simple() { var config = new ConfigFile { Id = nameof(Simple), Namespace = nameof(Simple), Includes = { new IncludeRule { File = "interface.h", Attach = true, Namespace = nameof(Simple) } }, Bindings = { new BindRule("int", "System.Int32") } }; var iface = new CppInterface { Name = "Interface", TotalMethodCount = 1 }; iface.Add(new CppMethod { Name = "method", ReturnValue = new CppReturnValue { TypeName = "int" } }); var include = new CppInclude { Name = "interface" }; include.Add(iface); var module = new CppModule(); module.Add(include); var(solution, _) = MapModel(module, config); Assert.Single(solution.EnumerateDescendants().OfType <CsInterface>()); var csIface = solution.EnumerateDescendants().OfType <CsInterface>().First(); Assert.Single(csIface.Methods); var method = csIface.Methods.First(); Assert.Equal(0, method.Offset); Assert.IsType <CsFundamentalType>(method.ReturnValue.PublicType); Assert.Equal(typeof(int), ((CsFundamentalType)method.ReturnValue.PublicType).Type); }
public void NativePrimitiveTypeNotLarge() { var config = new ConfigFile { Id = nameof(NativePrimitiveTypeNotLarge), Namespace = nameof(NativePrimitiveTypeNotLarge), Includes = { new IncludeRule { File = "pointerSize.h", Attach = true, Namespace = nameof(NativePrimitiveTypeNotLarge) } }, Extension = { new DefineExtensionRule { Struct = "NativePrimitiveType", SizeOf = 16, IsNativePrimitive = true, } }, Bindings = { new BindRule("NativePrimitive", "NativePrimitiveType") } }; var iface = new CppInterface("Interface"); iface.Add(new CppMethod("method") { ReturnValue = new CppReturnValue { TypeName = "NativePrimitive" } }); var include = new CppInclude("pointerSize"); include.Add(iface); var module = new CppModule("SharpGenTestModule"); module.Add(include); var(solution, _) = MapModel(module, config); Assert.Single(solution.EnumerateDescendants <CsInterface>()); var csIface = solution.EnumerateDescendants <CsInterface>().First(); Assert.Single(csIface.Methods); var method = csIface.Methods.First(); Assert.False(method.IsReturnStructLarge); Assert.False(Logger.HasErrors); }
public void DualCallbackFlowsNativeImplementation() { var config = new ConfigFile { Id = nameof(Simple), Namespace = nameof(Simple), Includes = { new IncludeRule { File = "interface.h", Attach = true, Namespace = nameof(Simple) } }, Bindings = { new BindRule("int", "System.Int32") }, Mappings = { new MappingRule { Interface = "Interface", IsCallbackInterface = true, IsDualCallbackInterface = true } } }; var iface = new CppInterface { Name = "Interface", TotalMethodCount = 1 }; iface.Add(new CppMethod { Name = "method", ReturnValue = new CppReturnValue { TypeName = "int" } }); var include = new CppInclude { Name = "interface" }; include.Add(iface); var module = new CppModule(); module.Add(include); var(_, defines) = GetConsumerBindings(module, config); var interfaceDefine = defines.First(define => define.Interface == "Simple.Interface"); Assert.Equal("Simple.InterfaceNative", interfaceDefine.NativeImplementation); }
public void ContextRuleLimitsWhereMappingRuleExecutes() { var config = new ConfigFile { Id = nameof(ContextRuleLimitsWhereMappingRuleExecutes), Namespace = nameof(ContextRuleLimitsWhereMappingRuleExecutes), Includes = { new IncludeRule { Attach = true, File = "cppEnum.h", Namespace = nameof(ContextRuleLimitsWhereMappingRuleExecutes) }, new IncludeRule { Attach = true, File = "secondFile.h", Namespace = nameof(ContextRuleLimitsWhereMappingRuleExecutes) } }, Mappings = { new Config.ContextRule("cppEnum"), new MappingRule { Enum = "AnotherEnum", MappingNameFinal = "NewEnum" }, new ClearContextRule() } }; var cppModel = new CppModule(); var cppInclude = new CppInclude { Name = "cppEnum" }; var cppEnum = new CppEnum { Name = "TestEnum" }; var secondInclude = new CppInclude { Name = "secondFile" }; var cppEnum2 = new CppEnum { Name = "AnotherEnum" }; cppEnum.AddEnumItem("Element1", "0"); cppEnum.AddEnumItem("Element2", "1"); cppInclude.Add(cppEnum); cppModel.Add(cppInclude); var(solution, _) = MapModel(cppModel, config); Assert.Empty(solution.EnumerateDescendants().OfType <CsEnum>().Where(csEnum => csEnum.Name == "AnotherEnum")); }
/// <summary> /// Initialize this Parser from a config file. /// </summary> public void Initialize(ConfigMapping config) { masterConfig = config; masterHeaderFile = masterConfig.Id + ".hpp"; // Config is updated if ForceParsing is true masterConfigHasChanged = ForceParsing; // Create CppModule instance masterCppModule = new CppModule(); // Create CastXml instance castXML = new CastXML(); castXML.ExecutablePath = CastXmlExecutablePath; castXML.VcToolsPath = VcToolsPath; // Add current directory for gccxml castXML.IncludeDirs.Add(new IncludeDirMapping(Environment.CurrentDirectory)); // Configure gccxml with include directory foreach (ConfigMapping configFile in masterConfig.ConfigFilesLoaded) { // Add all include directories foreach (IncludeDirMapping includeDir in configFile.IncludeDirs) { castXML.IncludeDirs.Add(includeDir); } } // Check if the file has any includes related config List <string> filesWithIncludes = new List <string>(); foreach (ConfigMapping configFile in masterConfig.ConfigFilesLoaded) { bool isWithInclude = false; // Add this config file as an include to process includeToProcess.Add(configFile.Id, true); if (configFile.IncludeDirs.Count > 0) { isWithInclude = true; } if (configFile.Includes.Count > 0) { isWithInclude = true; } if (configFile.References.Count > 0) { isWithInclude = true; } // If this config file has any include rules if (isWithInclude) { filesWithIncludes.Add(configFile.Id); } } // Write include files foreach (ConfigMapping configFile in masterConfig.ConfigFilesLoaded) { // Check if config have includes if (!filesWithIncludes.Contains(configFile.Id)) { // Skip, process next config continue; } var outputConfig = new StringWriter(); outputConfig.WriteLine("// pylon-node include config for {0} - Version {1}", configFile.Id, Version); outputConfig.WriteLine("// Do not edit this file, is generated by pylon-node-gen"); outputConfig.WriteLine("//"); outputConfig.WriteLine(); // Write includes foreach (IncludeMapping includeMapping in configFile.Includes) { CppInclude cppInclude = masterCppModule.FindInclude(includeMapping.Id); if (cppInclude == null) { includeToProcess.Add(includeMapping.Id, true); cppInclude = new CppInclude(); cppInclude.Name = includeMapping.Id; masterCppModule.Add(cppInclude); } outputConfig.WriteLine("#include <{0}>", includeMapping.File); } // Write includes to references foreach (ConfigMapping reference in configFile.References) { if (filesWithIncludes.Contains(reference.Id)) { outputConfig.WriteLine("#include \"{0}\"", reference.Id + ".hpp"); } } outputConfig.Close(); string outputConfigString = outputConfig.ToString(); string outputConfigFile = configFile.Id + ".hpp"; // Test if Last config file was generated. If not, then we need to generate it // If it exists, then we need to test if it is the same than previous run configFile.IsConfigUpdated = ForceParsing; if (File.Exists(outputConfigFile) && !ForceParsing) { configFile.IsConfigUpdated = outputConfigString != File.ReadAllText(outputConfigFile); } else { configFile.IsConfigUpdated = true; } // Just write the header file when the file is updated or new if (configFile.IsConfigUpdated) { log.Info("Config file changed for C++ headers (module: " + configFile.Id + ", config: " + configFile.FilePath + ")"); masterConfigHasChanged = true; var fileWriter = new StreamWriter(outputConfigFile); fileWriter.Write(outputConfigString); fileWriter.Close(); } } }