Browse Source

Massive update to the codebase.

- Removed reliance on T4 text templates that were proving to be a portability problem.
 - Refactored the generator design to make a little more sense.
 - Moved the examples to their own projects.
 - Improved the build system to only use one unified output folder.
 - Added much improved template support.
 - Added work-in-progress C++/CLI generator backend.
 - Added the concept of type maps.
pull/1/head
triton 13 years ago
parent
commit
f5fcef50f1
  1. 3
      .gitignore
  2. 24
      build/Parser.vcxproj
  3. 32
      build/Parser.vcxproj.filters
  4. 41
      build/cxxi.sln
  5. 2
      build/premake4.lua
  6. 91
      examples/Clang/Clang.cs
  7. 63
      examples/Clang/Clang.csproj
  8. 36
      examples/Clang/Properties/AssemblyInfo.cs
  9. 141
      examples/Flood/Flood.cs
  10. 63
      examples/Flood/Flood.csproj
  11. 36
      examples/Flood/Properties/AssemblyInfo.cs
  12. 36
      examples/SDL/Properties/AssemblyInfo.cs
  13. 74
      examples/SDL/SDL.cs
  14. 63
      examples/SDL/SDL.csproj
  15. 3
      src/Bridge/Bridge.csproj
  16. 205
      src/Bridge/Class.cs
  17. 12
      src/Bridge/Comment.cs
  18. 178
      src/Bridge/Declaration.cs
  19. 108
      src/Bridge/Enumeration.cs
  20. 43
      src/Bridge/Field.cs
  21. 133
      src/Bridge/Function.cs
  22. 204
      src/Bridge/Library.cs
  23. 114
      src/Bridge/Method.cs
  24. 271
      src/Bridge/Namespace.cs
  25. 63
      src/Bridge/Property.cs
  26. 57
      src/Bridge/Template.cs
  27. 765
      src/Bridge/Type.cs
  28. 6
      src/Generator.Tests/App.config
  29. 67
      src/Generator.Tests/Generator.Tests.csproj
  30. 21
      src/Generator.Tests/TestCLITypePrinter.cs
  31. 4
      src/Generator.Tests/packages.config
  32. 224
      src/Generator/CodeGenerator.cs
  33. 63
      src/Generator/Filter.cs
  34. 271
      src/Generator/Generator.cs
  35. 100
      src/Generator/Generator.csproj
  36. 22
      src/Generator/Generator.csproj.user
  37. 327
      src/Generator/Generators/CLI/CLIHeadersTemplate.cs
  38. 449
      src/Generator/Generators/CLI/CLIHelpers.cs
  39. 412
      src/Generator/Generators/CLI/CLIMarshal.cs
  40. 285
      src/Generator/Generators/CLI/CLISourcesTemplate.cs
  41. 142
      src/Generator/Generators/CSharp/CSharpHelpers.cs
  42. 261
      src/Generator/Generators/CSharp/CSharpModule.tt
  43. 94
      src/Generator/Generators/Generator.cs
  44. 76
      src/Generator/Generators/Template.cs
  45. 34
      src/Generator/Glob.cs
  46. 79
      src/Generator/Helpers.cs
  47. 68
      src/Generator/Libraries/Clang.cs
  48. 60
      src/Generator/Libraries/SDL.cs
  49. 263
      src/Generator/LibraryHelpers.cs
  50. 76
      src/Generator/Pass.cs
  51. 50
      src/Generator/PassBuilder.cs
  52. 158
      src/Generator/Program.cs
  53. 246
      src/Generator/Templates/CSharpModule.tt
  54. 313
      src/Generator/Transform.cs
  55. 224
      src/Generator/Transforms/Renames.cs
  56. 164
      src/Generator/Transforms/Transform.cs
  57. 187
      src/Generator/Types/Checker.cs
  58. 84
      src/Generator/Types/Std/Stdlib.cs
  59. 92
      src/Generator/Types/TypeMap.cs
  60. 276
      src/Generator/Types/Types.cs
  61. 34
      src/Generator/Utils/Glob.cs
  62. 0
      src/Generator/Utils/Options.cs
  63. 176
      src/Generator/Utils/Utils.cs
  64. 3
      src/Generator/app.config
  65. 4
      src/Parser/Main.cpp
  66. 596
      src/Parser/Parser.cpp
  67. 20
      src/Parser/Parser.h

3
.gitignore vendored

@ -16,3 +16,6 @@ tests/output @@ -16,3 +16,6 @@ tests/output
src/generator/generator
*.pc
.DS_Store
vs2010
llvm
obj

24
build/Parser.vcxproj

@ -40,11 +40,11 @@ @@ -40,11 +40,11 @@
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\build\bin\</OutDir>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">bin\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">obj\Debug\</IntDir>
<TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Parser_d</TargetName>
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\bin\</OutDir>
<OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">bin\</OutDir>
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">obj\Release\</IntDir>
<TargetName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Parser</TargetName>
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
@ -53,7 +53,7 @@ @@ -53,7 +53,7 @@
<ClCompile>
<AdditionalOptions>/wd4146 /wd4244 /wd4800 /wd4345 /wd4355 /wd4996 /wd4624 /wd4291 /clr %(AdditionalOptions)</AdditionalOptions>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..\..\auth\LLVM\include;..\..\..\auth\LLVM\build\include;..\..\..\auth\LLVM\tools\clang\include;..\..\..\auth\LLVM\build\tools\clang\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\deps\llvm\include;..\deps\llvm\build\include;..\deps\llvm\tools\clang\include;..\deps\llvm\build\tools\clang\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
@ -76,7 +76,7 @@ @@ -76,7 +76,7 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>LLVMSupport.lib;LLVMAsmParser.lib;LLVMMC.lib;LLVMMCParser.lib;LLVMX86AsmParser.lib;LLVMX86AsmPrinter.lib;LLVMX86Desc.lib;LLVMX86Info.lib;LLVMX86Utils.lib;clangAnalysis.lib;clangBasic.lib;clangAST.lib;clangDriver.lib;clangEdit.lib;clangFrontend.lib;clangLex.lib;clangParse.lib;clangSema.lib;clangSerialization.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<AdditionalLibraryDirectories>..\..\..\auth\LLVM\build\lib\Debug;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalLibraryDirectories>..\deps\llvm\build\lib\Debug;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<EntryPointSymbol>
</EntryPointSymbol>
</Link>
@ -113,19 +113,13 @@ @@ -113,19 +113,13 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="..\..\src\Parser\CXXABI.h" />
<ClInclude Include="..\..\src\Parser\Interop.h" />
<ClInclude Include="..\..\src\Parser\Parser.h" />
<ClInclude Include="..\src\Parser\CXXABI.h" />
<ClInclude Include="..\src\Parser\Interop.h" />
<ClInclude Include="..\src\Parser\Parser.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\src\Parser\Main.cpp">
</ClCompile>
<ClCompile Include="..\..\src\Parser\Parser.cpp">
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="..\Parser.lua" />
<None Include="..\premake4.lua" />
<ClCompile Include="..\src\Parser\Main.cpp" />
<ClCompile Include="..\src\Parser\Parser.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">

32
build/Parser.vcxproj.filters

@ -1,34 +1,12 @@ @@ -1,34 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="src">
<UniqueIdentifier>{254AD2D5-F792-C842-A59A-EFC933E51C60}</UniqueIdentifier>
</Filter>
<Filter Include="src\Parser">
<UniqueIdentifier>{35E5E65B-7ABF-A54D-AEC8-338693EF5D27}</UniqueIdentifier>
</Filter>
<ClInclude Include="..\src\Parser\CXXABI.h" />
<ClInclude Include="..\src\Parser\Interop.h" />
<ClInclude Include="..\src\Parser\Parser.h" />
</ItemGroup>
<ItemGroup>
<None Include="..\Parser.lua" />
<None Include="..\premake4.lua" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\src\Parser\CXXABI.h">
<Filter>src\Parser</Filter>
</ClInclude>
<ClInclude Include="..\..\src\Parser\Interop.h">
<Filter>src\Parser</Filter>
</ClInclude>
<ClInclude Include="..\..\src\Parser\Parser.h">
<Filter>src\Parser</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\src\Parser\Main.cpp">
<Filter>src\Parser</Filter>
</ClCompile>
<ClCompile Include="..\..\src\Parser\Parser.cpp">
<Filter>src\Parser</Filter>
</ClCompile>
<ClCompile Include="..\src\Parser\Main.cpp" />
<ClCompile Include="..\src\Parser\Parser.cpp" />
</ItemGroup>
</Project>

41
build/cxxi.sln

@ -8,11 +8,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "gcc-generator", "src\gcc-ge @@ -8,11 +8,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "gcc-generator", "src\gcc-ge
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Legacy", "Legacy", "{CC1EED48-730C-417A-9390-525BBCB518DA}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Parser", "vs2010\Parser.vcxproj", "{C8BF56CF-4CD2-324A-9092-43F508104956}"
ProjectSection(ProjectDependencies) = postProject
{6BEB8FA2-97AA-40B7-AB92-42F6EDDC4490} = {6BEB8FA2-97AA-40B7-AB92-42F6EDDC4490}
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bridge", "..\src\Bridge\Bridge.csproj", "{6BEB8FA2-97AA-40B7-AB92-42F6EDDC4490}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Generator", "..\src\Generator\Generator.csproj", "{73499B8E-A6A4-42FF-AB8A-754CE2780777}"
@ -26,11 +21,13 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Generator.Tests", "..\src\G @@ -26,11 +21,13 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Generator.Tests", "..\src\G
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Examples", "Examples", "{018A0BF1-788C-4366-BC67-8C4E7D14F5B3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Generator.Clang", "..\examples\Clang\Generator.Clang.csproj", "{5439BC03-FA91-4D93-9EA0-4E550C1610F3}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Clang", "..\examples\Clang\Clang.csproj", "{5439BC03-FA91-4D93-9EA0-4E550C1610F3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Flood", "..\examples\Flood\Flood.csproj", "{28455425-1A80-458E-952C-5B0069866AAD}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Generator.Flood", "..\examples\Flood\Generator.Flood.csproj", "{28455425-1A80-458E-952C-5B0069866AAD}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SDL", "..\examples\SDL\SDL.csproj", "{8D642354-FBD5-4551-95A6-09D369B83167}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Generator.SDL", "..\examples\SDL\Generator.SDL.csproj", "{8D642354-FBD5-4551-95A6-09D369B83167}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Parser", "Parser.vcxproj", "{C8BF56CF-4CD2-324A-9092-43F508104956}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -85,20 +82,6 @@ Global @@ -85,20 +82,6 @@ Global
{AD0F9378-789C-4AF1-B0DD-6DD9A63C3401}.Release|Win32.ActiveCfg = Release|x86
{AD0F9378-789C-4AF1-B0DD-6DD9A63C3401}.Release|x86.ActiveCfg = Release|x86
{AD0F9378-789C-4AF1-B0DD-6DD9A63C3401}.Release|x86.Build.0 = Release|x86
{C8BF56CF-4CD2-324A-9092-43F508104956}.Debug|Any CPU.ActiveCfg = Debug|Win32
{C8BF56CF-4CD2-324A-9092-43F508104956}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
{C8BF56CF-4CD2-324A-9092-43F508104956}.Debug|Mixed Platforms.Build.0 = Debug|Win32
{C8BF56CF-4CD2-324A-9092-43F508104956}.Debug|Win32.ActiveCfg = Debug|Win32
{C8BF56CF-4CD2-324A-9092-43F508104956}.Debug|Win32.Build.0 = Debug|Win32
{C8BF56CF-4CD2-324A-9092-43F508104956}.Debug|x86.ActiveCfg = Debug|Win32
{C8BF56CF-4CD2-324A-9092-43F508104956}.Debug|x86.Build.0 = Debug|Win32
{C8BF56CF-4CD2-324A-9092-43F508104956}.Release|Any CPU.ActiveCfg = Release|Win32
{C8BF56CF-4CD2-324A-9092-43F508104956}.Release|Mixed Platforms.ActiveCfg = Release|Win32
{C8BF56CF-4CD2-324A-9092-43F508104956}.Release|Mixed Platforms.Build.0 = Release|Win32
{C8BF56CF-4CD2-324A-9092-43F508104956}.Release|Win32.ActiveCfg = Release|Win32
{C8BF56CF-4CD2-324A-9092-43F508104956}.Release|Win32.Build.0 = Release|Win32
{C8BF56CF-4CD2-324A-9092-43F508104956}.Release|x86.ActiveCfg = Release|Win32
{C8BF56CF-4CD2-324A-9092-43F508104956}.Release|x86.Build.0 = Release|Win32
{6BEB8FA2-97AA-40B7-AB92-42F6EDDC4490}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6BEB8FA2-97AA-40B7-AB92-42F6EDDC4490}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6BEB8FA2-97AA-40B7-AB92-42F6EDDC4490}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
@ -189,6 +172,20 @@ Global @@ -189,6 +172,20 @@ Global
{8D642354-FBD5-4551-95A6-09D369B83167}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{8D642354-FBD5-4551-95A6-09D369B83167}.Release|Win32.ActiveCfg = Release|Any CPU
{8D642354-FBD5-4551-95A6-09D369B83167}.Release|x86.ActiveCfg = Release|Any CPU
{C8BF56CF-4CD2-324A-9092-43F508104956}.Debug|Any CPU.ActiveCfg = Debug|Win32
{C8BF56CF-4CD2-324A-9092-43F508104956}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
{C8BF56CF-4CD2-324A-9092-43F508104956}.Debug|Mixed Platforms.Build.0 = Debug|Win32
{C8BF56CF-4CD2-324A-9092-43F508104956}.Debug|Win32.ActiveCfg = Debug|Win32
{C8BF56CF-4CD2-324A-9092-43F508104956}.Debug|Win32.Build.0 = Debug|Win32
{C8BF56CF-4CD2-324A-9092-43F508104956}.Debug|x86.ActiveCfg = Debug|Win32
{C8BF56CF-4CD2-324A-9092-43F508104956}.Debug|x86.Build.0 = Debug|Win32
{C8BF56CF-4CD2-324A-9092-43F508104956}.Release|Any CPU.ActiveCfg = Release|Win32
{C8BF56CF-4CD2-324A-9092-43F508104956}.Release|Mixed Platforms.ActiveCfg = Release|Win32
{C8BF56CF-4CD2-324A-9092-43F508104956}.Release|Mixed Platforms.Build.0 = Release|Win32
{C8BF56CF-4CD2-324A-9092-43F508104956}.Release|Win32.ActiveCfg = Release|Win32
{C8BF56CF-4CD2-324A-9092-43F508104956}.Release|Win32.Build.0 = Release|Win32
{C8BF56CF-4CD2-324A-9092-43F508104956}.Release|x86.ActiveCfg = Release|Win32
{C8BF56CF-4CD2-324A-9092-43F508104956}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

2
build/premake4.lua

@ -11,7 +11,7 @@ common_msvc_copts = @@ -11,7 +11,7 @@ common_msvc_copts =
"/wd4355", "/wd4996", "/wd4624", "/wd4291"
}
solution "Cxxi2"
solution "Cxxi"
configurations
{

91
examples/Clang/Clang.cs

@ -0,0 +1,91 @@ @@ -0,0 +1,91 @@
using Cxxi.Generators;
using Cxxi.Passes;
using Cxxi.Templates;
using Generator = Cxxi.Generators.Generator;
namespace Cxxi
{
/// <summary>
/// Transform the Clang library declarations to something more .NET friendly.
/// </summary>
class Clang : ILibrary
{
public void Preprocess(LibraryHelpers g)
{
//g.SetNameOfEnumWithMatchingItem("SDL_LOG_CATEGORY_CUSTOM", "LogCategory");
// Clean up types
g.FindClass("CXString").IsOpaque = true;
g.FindClass("CXSourceLocation").IsOpaque = true;
g.FindClass("CXSourceRange").IsOpaque = true;
g.FindClass("CXCursor").IsOpaque = true;
g.FindClass("CXType").IsOpaque = true;
g.FindClass("CXToken").IsOpaque = true;
g.FindClass("CXIdxLoc").IsOpaque = true;
g.FindClass("CXTranslationUnitImpl").IsOpaque = true;
}
public void Postprocess(LibraryHelpers g)
{
g.FindEnum("CompletionContext").SetFlags();
g.FindClass("String").Name = "CXString";
//gen.SetNameOfEnumWithName("LOG_CATEGORY", "LogCategory");
}
public void Postprocess(Generators.Generator generator)
{
}
public void SetupPasses(PassBuilder p)
{
p.RemovePrefix("CX");
p.RemovePrefix("clang_");
p.RenameWithPattern("^_", string.Empty, RenameTargets.Any);
// Clean up enums
p.RemovePrefixEnumItem("ChildVisit_");
p.RemovePrefixEnumItem("Comment_");
p.RemovePrefixEnumItem("Availability_");
p.RemovePrefixEnumItem("GlobalOpt_");
p.RemovePrefixEnumItem("Diagnostic_");
p.RemovePrefixEnumItem("LoadDiag_");
p.RemovePrefixEnumItem("TranslationUnit_");
p.RemovePrefixEnumItem("SaveTranslationUnit_");
p.RemovePrefixEnumItem("SaveError_");
p.RemovePrefixEnumItem("TranslationUnit_");
p.RemovePrefixEnumItem("Reparse_");
p.RemovePrefixEnumItem("TUResourceUsage_");
p.RemovePrefixEnumItem("Cursor_");
p.RemovePrefixEnumItem("Linkage_");
p.RemovePrefixEnumItem("Language_");
p.RemovePrefixEnumItem("Type_");
p.RemovePrefixEnumItem("CallingConv_");
p.RemovePrefixEnumItem("CommentInlineCommandRenderKind_");
p.RemovePrefixEnumItem("CommentParamPassDirection_");
p.RemovePrefixEnumItem("NameRange_");
p.RemovePrefixEnumItem("Token_");
p.RemovePrefixEnumItem("CompletionChunk_");
p.RemovePrefixEnumItem("CodeComplete_");
p.RemovePrefixEnumItem("CompletionContext_");
p.RemovePrefixEnumItem("Visit_");
p.RemovePrefixEnumItem("IdxEntity_");
p.RemovePrefixEnumItem("IdxEntityLang_");
p.RemovePrefixEnumItem("IdxAttr_");
p.RemovePrefixEnumItem("IdxObjCContainer_");
p.RemovePrefixEnumItem("IdxEntityRef_");
p.RemovePrefixEnumItem("IndexOpt_");
p.RemovePrefixEnumItem("IdxObjCContainer_");
}
public void GenerateStart(TextTemplate template)
{
throw new System.NotImplementedException();
}
public void GenerateAfterNamespaces(TextTemplate template)
{
throw new System.NotImplementedException();
}
}
}

63
examples/Clang/Clang.csproj

@ -0,0 +1,63 @@ @@ -0,0 +1,63 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{5439BC03-FA91-4D93-9EA0-4E550C1610F3}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Clang</RootNamespace>
<AssemblyName>Clang</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\..\build\bin\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>..\..\build\bin\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Clang.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Bridge\Bridge.csproj">
<Project>{6BEB8FA2-97AA-40B7-AB92-42F6EDDC4490}</Project>
<Name>Bridge</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Generator\Generator.csproj">
<Project>{73499B8E-A6A4-42FF-AB8A-754CE2780777}</Project>
<Name>Generator</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

36
examples/Clang/Properties/AssemblyInfo.cs

@ -0,0 +1,36 @@ @@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Clang")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Clang")]
[assembly: AssemblyCopyright("Copyright © 2013")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("e7c52cd3-e09e-43ba-91e4-82bc31315f7c")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

141
examples/Flood/Flood.cs

@ -0,0 +1,141 @@ @@ -0,0 +1,141 @@
using Cxxi.Generators;
using Cxxi.Generators.CLI;
using Cxxi.Passes;
using Cxxi.Types;
namespace Cxxi.Libraries
{
/// <summary>
/// Transform the Flush library declarations to something more .NET friendly.
/// </summary>
class Flush : ILibrary
{
public void Preprocess(LibraryHelpers g)
{
g.IgnoreModulessWithName("API.h");
g.IgnoreModulessWithName("Concurrency.h");
g.IgnoreModulessWithName("ConcurrentQueue.h");
g.IgnoreModulessWithName("Delegate.h");
g.IgnoreModulessWithName("Event.h");
g.IgnoreModulessWithName("Handle.h");
//g.IgnoreModulessWithName("Memory.h");
g.IgnoreModulessWithName("Object.h");
g.IgnoreModulessWithName("Pointers.h");
g.IgnoreModulessWithName("References.h");
//g.IgnoreModulessWithName("Reflection.h");
g.IgnoreModulessWithName("Serialization.h");
//Core
g.SetClassAsValueType("StringHash");
g.IgnoreClassWithName("RawStringCompare");
g.IgnoreFunctionWithName("LogCreate");
g.SetClassAsValueType("LogEntry");
g.SetClassAsValueType("FileWatchEvent");
g.SetClassAsValueType("ExtensionMetadata");
g.IgnoreClassWithName("StreamFuncs");
// Math
g.SetClassAsValueType("ColorP");
g.SetClassAsValueType("Color");
g.SetClassAsValueType("Vector2P");
g.SetClassAsValueType("Vector2");
g.SetClassAsValueType("Vector2i");
g.SetClassAsValueType("Vector3P");
g.SetClassAsValueType("Vector3");
g.SetClassAsValueType("Vector4");
g.SetClassAsValueType("EulerAngles");
g.SetClassAsValueType("QuaternionP");
g.SetClassAsValueType("Quaternion");
// Resources
g.IgnoreFunctionWithName("ResourcesInitialize");
g.IgnoreFunctionWithName("ResourcesDeinitialize");
g.SetClassAsValueType("ResourceEvent");
g.SetClassAsValueType("ResourceLoadOption");
g.SetClassAsValueType("ResourceLoadOptions");
// Engine
g.IgnoreClassMethodWithName("Engine", "addSubsystem");
}
public void Postprocess(LibraryHelpers generator)
{
}
public void SetupPasses(PassBuilder p)
{
p.RenameDeclsCase(RenameTargets.Function | RenameTargets.Method | RenameTargets.Field,
RenameCasePattern.UpperCamelCase);
}
public void GenerateStart(TextTemplate template)
{
template.WriteLine("/************************************************************************");
template.WriteLine("*");
template.WriteLine("* Flood Project \u00A9 (2008-201x)");
template.WriteLine("* Licensed under the simplified BSD license. All rights reserved.");
template.WriteLine("*");
template.WriteLine("************************************************************************/");
template.NewLine();
if (template is CLISourcesTemplate)
template.WriteLine("#include \"_Marshal.h\"");
}
public void GenerateAfterNamespaces(TextTemplate template)
{
if (template is CLISourcesTemplate)
template.WriteLine("using namespace clix;");
}
}
namespace Types.Flush
{
[TypeMap("RefPtr")]
public class RefPtr : TypeMap
{
public override string Signature()
{
var type = Type as TemplateSpecializationType;
return string.Format("{0}", type.Arguments[0].Type);
}
public override string MarshalToNative(MarshalContext ctx)
{
throw new System.NotImplementedException();
}
public override string MarshalFromNative(MarshalContext ctx)
{
return "nullptr";
}
}
[TypeMap("ResourceHandle")]
public class ResourceHandle : TypeMap
{
public override string Signature()
{
return "uint";
}
public override string MarshalToNative(MarshalContext ctx)
{
return string.Format("(HandleId){0}", ctx.Parameter.Name);
}
public override string MarshalFromNative(MarshalContext ctx)
{
return string.Format("(HandleId){0}", ctx.ReturnVarName);
}
}
[TypeMap("Path")]
[TypeMap("String")]
[TypeMap("StringWide")]
public class String : Cxxi.Types.Std.String
{
}
}
}

63
examples/Flood/Flood.csproj

@ -0,0 +1,63 @@ @@ -0,0 +1,63 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{28455425-1A80-458E-952C-5B0069866AAD}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Flood</RootNamespace>
<AssemblyName>Flood</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\..\build\bin\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>..\..\build\bin\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Flood.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Bridge\Bridge.csproj">
<Project>{6BEB8FA2-97AA-40B7-AB92-42F6EDDC4490}</Project>
<Name>Bridge</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Generator\Generator.csproj">
<Project>{73499b8e-a6a4-42ff-ab8a-754ce2780777}</Project>
<Name>Generator</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

36
examples/Flood/Properties/AssemblyInfo.cs

@ -0,0 +1,36 @@ @@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Flood")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Flood")]
[assembly: AssemblyCopyright("Copyright © 2013")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("e9efb51b-baab-4008-8924-47c33761bf0f")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

36
examples/SDL/Properties/AssemblyInfo.cs

@ -0,0 +1,36 @@ @@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("SDL")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("SDL")]
[assembly: AssemblyCopyright("Copyright © 2013")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("5934cefb-a2b3-4556-901b-4d512f28aecc")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

74
examples/SDL/SDL.cs

@ -0,0 +1,74 @@ @@ -0,0 +1,74 @@
using Cxxi.Generators;
namespace Cxxi
{
/// <summary>
/// Transform the SDL library declarations to something more .NET friendly.
/// </summary>
class SDL : ILibrary
{
public void Preprocess(LibraryHelpers g)
{
g.IgnoreEnumWithMatchingItem("SDL_FALSE");
g.IgnoreEnumWithMatchingItem("DUMMY_ENUM_VALUE");
g.SetNameOfEnumWithMatchingItem("SDL_SCANCODE_UNKNOWN", "ScanCode");
g.SetNameOfEnumWithMatchingItem("SDLK_UNKNOWN", "Key");
g.SetNameOfEnumWithMatchingItem("KMOD_NONE", "KeyModifier");
g.SetNameOfEnumWithMatchingItem("SDL_LOG_CATEGORY_CUSTOM", "LogCategory");
g.GenerateEnumFromMacros("InitFlags", "SDL_INIT_(.*)").SetFlags();
g.GenerateEnumFromMacros("Endianness", "SDL_(.*)_ENDIAN");
g.GenerateEnumFromMacros("InputState", "SDL_RELEASED", "SDL_PRESSED");
g.GenerateEnumFromMacros("AlphaState", "SDL_ALPHA_(.*)");
g.GenerateEnumFromMacros("HatState", "SDL_HAT_(.*)");
g.IgnoreModulessWithName("SDL_atomic*");
g.IgnoreModulessWithName("SDL_endian*");
g.IgnoreModulessWithName("SDL_main*");
g.IgnoreModulessWithName("SDL_mutex*");
g.IgnoreModulessWithName("SDL_stdinc*");
//g.IgnoreModuleWithName("SDL_error");
g.IgnoreEnumWithMatchingItem("SDL_ENOMEM");
g.IgnoreFunctionWithName("SDL_Error");
}
public void Postprocess(LibraryHelpers generator)
{
generator.SetNameOfEnumWithName("PIXELTYPE", "PixelType");
generator.SetNameOfEnumWithName("BITMAPORDER", "BitmapOrder");
generator.SetNameOfEnumWithName("PACKEDORDER", "PackedOrder");
generator.SetNameOfEnumWithName("ARRAYORDER", "ArrayOrder");
generator.SetNameOfEnumWithName("PACKEDLAYOUT", "PackedLayout");
generator.SetNameOfEnumWithName("PIXELFORMAT", "PixelFormats");
generator.SetNameOfEnumWithName("assert_state", "AssertState");
generator.SetClassBindName("assert_data", "AssertData");
generator.SetNameOfEnumWithName("eventaction", "EventAction");
//gen.SetNameOfEnumWithName("LOG_CATEGORY", "LogCategory");
}
public void SetupPasses(PassBuilder p)
{
p.RemovePrefix("SDL_");
p.RemovePrefix("SCANCODE_");
p.RemovePrefix("SDLK_");
p.RemovePrefix("KMOD_");
p.RemovePrefix("LOG_CATEGORY_");
}
public void GenerateStart(TextTemplate template)
{
throw new System.NotImplementedException();
}
public void GenerateAfterNamespaces(TextTemplate template)
{
throw new System.NotImplementedException();
}
}
}

63
examples/SDL/SDL.csproj

@ -0,0 +1,63 @@ @@ -0,0 +1,63 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{8D642354-FBD5-4551-95A6-09D369B83167}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>SDL</RootNamespace>
<AssemblyName>SDL</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\..\build\bin\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SDL.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Bridge\Bridge.csproj">
<Project>{6BEB8FA2-97AA-40B7-AB92-42F6EDDC4490}</Project>
<Name>Bridge</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\Generator\Generator.csproj">
<Project>{73499B8E-A6A4-42FF-AB8A-754CE2780777}</Project>
<Name>Generator</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

3
src/Bridge/Bridge.csproj

@ -17,7 +17,7 @@ @@ -17,7 +17,7 @@
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\..\bin\</OutputPath>
<OutputPath>..\..\build\bin\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
@ -51,6 +51,7 @@ @@ -51,6 +51,7 @@
<Compile Include="Namespace.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Property.cs" />
<Compile Include="Template.cs" />
<Compile Include="Type.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

205
src/Bridge/Class.cs

@ -2,95 +2,118 @@ using System.Collections.Generic; @@ -2,95 +2,118 @@ using System.Collections.Generic;
namespace Cxxi
{
// A C++ access specifier.
public enum AccessSpecifier
{
Private,
Protected,
Public
}
// Represents a base class of a C++ class.
public class BaseClassSpecifier
{
public Class Class { get; set; }
public AccessSpecifier Access { get; set; }
public bool IsVirtual { get; set; }
BaseClassSpecifier(Class @class, AccessSpecifier access,
bool isVirtual = false)
{
Class = @class;
Access = access;
IsVirtual = isVirtual;
}
}
// Represents a C++ virtual function table.
public class VFTable
{
}
// Represents a C++ virtual base table.
public class VBTable
{
}
// Represents ABI-specific layout details for a class.
public class ClassLayout
{
public CppAbi ABI { get; set; }
public bool HasOwnVFTable { get; set; }
public VFTable VirtualFunctions { get; set; }
public VBTable VirtualBases { get; set; }
}
// Represents a C++ record declaration.
public class Class : Declaration
{
public List<BaseClassSpecifier> Bases;
public List<Class> NestedClasses;
public List<Enumeration> NestedEnums;
public List<Field> Fields;
public List<Property> Properties;
public List<Method> Methods;
// True if the record is a POD (Plain Old Data) type.
public bool IsPOD;
// ABI-specific class layout.
public List<ClassLayout> Layouts { get; set; }
// True if class only provides pure virtual methods.
public bool IsAbstract;
// True if the type is to be treated as a union.
public bool IsUnion;
// True if the type is to be treated as opaque.
public bool IsOpaque;
public string TemplateName { get; set; }
public string TemplateClassName { get; set; }
public Class()
{
Bases = new List<BaseClassSpecifier>();
Fields = new List<Field>();
Properties = new List<Property>();
Methods = new List<Method>();
NestedClasses = new List<Class>();
NestedEnums = new List<Enumeration>();
IsAbstract = false;
IsUnion = false;
IsOpaque = false;
}
public bool HasBase
{
get { return Bases.Count > 0; }
}
}
// A C++ access specifier.
public enum AccessSpecifier
{
Private,
Protected,
Public
}
// Represents a base class of a C++ class.
public class BaseClassSpecifier
{
public Class Class { get; set; }
public AccessSpecifier Access { get; set; }
public bool IsVirtual { get; set; }
BaseClassSpecifier(Class @class, AccessSpecifier access,
bool isVirtual = false)
{
Class = @class;
Access = access;
IsVirtual = isVirtual;
}
}
// Represents a C++ virtual function table.
public class VFTable
{
}
// Represents a C++ virtual base table.
public class VBTable
{
}
// Represents ABI-specific layout details for a class.
public class ClassLayout
{
public CppAbi ABI { get; set; }
public bool HasOwnVFTable { get; set; }
public VFTable VirtualFunctions { get; set; }
public VBTable VirtualBases { get; set; }
}
public enum ClassType
{
ValueType,
RefType,
}
// Represents a C++ record Decl.
public class Class : Declaration
{
public List<BaseClassSpecifier> Bases;
public List<Class> NestedClasses;
public List<Enumeration> NestedEnums;
public List<Field> Fields;
public List<Property> Properties;
public List<Method> Methods;
// True if the record is a POD (Plain Old Data) type.
public bool IsPOD;
// Semantic type of the class.
public ClassType Type;
// ABI-specific class layout.
public List<ClassLayout> Layouts { get; set; }
// True if class provides pure virtual methods.
public bool IsAbstract;
// True if the type is to be treated as a union.
public bool IsUnion;
// True if the type is to be treated as opaque.
public bool IsOpaque;
public Class()
{
Bases = new List<BaseClassSpecifier>();
Fields = new List<Field>();
Properties = new List<Property>();
Methods = new List<Method>();
NestedClasses = new List<Class>();
NestedEnums = new List<Enumeration>();
IsAbstract = false;
IsUnion = false;
IsOpaque = false;
IsPOD = false;
Type = ClassType.RefType;
}
public bool HasBase
{
get { return Bases.Count > 0; }
}
public bool IsValueType
{
get { return Type == ClassType.ValueType; }
}
public bool IsRefType
{
get { return Type == ClassType.RefType; }
}
public override T Visit<T>(IDeclVisitor<T> visitor)
{
return visitor.VisitClassDecl(this);
}
}
}

12
src/Bridge/Comment.cs

@ -4,11 +4,11 @@ using System.Text; @@ -4,11 +4,11 @@ using System.Text;
namespace Cxxi
{
/// <summary>
/// Represents a C++ comment.
/// </summary>
public class Comment
{
/// <summary>
/// Represents a C++ comment.
/// </summary>
public class Comment
{
}
}
}

178
src/Bridge/Declaration.cs

@ -1,59 +1,123 @@ @@ -1,59 +1,123 @@
namespace Cxxi
using System;
namespace Cxxi
{
/// <summary>
/// Represents a C++ declaration.
/// </summary>
public class Declaration
{
// Name of the type.
public string Name;
// Doxygen-style brief comment.
public string BriefComment;
// Namespace the type is declared in.
//public Namespace Namespace;
// Wether the type should be ignored.
public bool Ignore;
// Contains a debug text of the type declaration.
public string DebugText;
public Declaration()
{
}
public Declaration(string name)
{
Name = name;
}
public override string ToString()
{
return Name;
}
}
/// <summary>
/// Represents a type definition in C++.
/// </summary>
public class Typedef : Declaration
{
/// Type defined.
public Type Type;
}
/// <summary>
/// Represents a C preprocessor macro definition.
/// </summary>
public class MacroDefine : Declaration
{
// Contains the macro definition text.
public string Expression;
public MacroDefine()
{
}
}
/// <summary>
/// Represents a C++ declaration.
/// </summary>
public abstract class Declaration
{
// Namespace the declaration is contained in.
public Namespace Namespace;
private string name;
// Name of the declaration.
public string Name
{
get { return name; }
set
{
name = value;
if (string.IsNullOrEmpty(OriginalName))
OriginalName = name;
}
}
// Name of the declaration.
public string OriginalName;
public string QualifiedOriginalName
{
get
{
return Namespace.IsRoot ? OriginalName
: string.Format("{0}::{1}", Namespace.Name, OriginalName);
}
}
// Doxygen-style brief comment.
public string BriefComment;
// Whether the declaration should be ignored.
public virtual bool Ignore
{
get
{
return ExplicityIgnored || Namespace.Ignore;
}
}
// Whether the declaration was explicitly ignored.
public bool ExplicityIgnored;
// Contains debug text about the declaration.
public string DebugText;
// True if the declaration is incomplete (no definition).
public bool IsIncomplete;
protected Declaration()
{
}
protected Declaration(string name)
{
Name = name;
}
public override string ToString()
{
return OriginalName;
}
public abstract T Visit<T>(IDeclVisitor<T> visitor);
}
/// <summary>
/// Represents a type definition in C++.
/// </summary>
public class TypedefDecl : Declaration
{
/// Type defined.
public Type Type;
public override T Visit<T>(IDeclVisitor<T> visitor)
{
return visitor.VisitTypedefDecl(this);
}
}
/// <summary>
/// Represents a C preprocessor macro definition.
/// </summary>
public class MacroDefinition : Declaration
{
// Contains the macro definition text.
public string Expression;
public MacroDefinition()
{
}
public override T Visit<T>(IDeclVisitor<T> visitor)
{
return visitor.VisitMacroDefinition(this);
}
}
public interface IDeclVisitor<out T>
{
T VisitDeclaration(Declaration decl);
T VisitClassDecl(Class @class);
T VisitFieldDecl(Field field);
T VisitFunctionDecl(Function function);
T VisitMethodDecl(Method method);
T VisitParameterDecl(Parameter parameter);
T VisitTypedefDecl(TypedefDecl typedef);
T VisitEnumDecl(Enumeration @enum);
T VisitClassTemplateDecl(ClassTemplate template);
T VisitFunctionTemplateDecl(FunctionTemplate template);
T VisitMacroDefinition(MacroDefinition macro);
}
}

108
src/Bridge/Enumeration.cs

@ -3,55 +3,61 @@ using System.Collections.Generic; @@ -3,55 +3,61 @@ using System.Collections.Generic;
namespace Cxxi
{
/// <summary>
/// Represents a C/C++ enumeration.
/// </summary>
public class Enumeration : Declaration
{
[Flags]
public enum EnumModifiers
{
Anonymous,
Scoped,
Flags
}
/// <summary>
/// Represents a C/C++ enumeration item.
/// </summary>
public class Item
{
public string Name;
public long Value;
public string Expression;
public string Comment;
public bool ExplicitValue = true;
}
public Enumeration()
{
Items = new List<Item>();
ItemsByName = new Dictionary<string, Item>();
Type = new BuiltinType(PrimitiveType.Int32);
}
public Enumeration AddItem(Item item)
{
Items.Add(item);
ItemsByName[item.Name] = item;
return this;
}
public Enumeration SetFlags()
{
Modifiers |= EnumModifiers.Flags;
return this;
}
public BuiltinType Type { get; set; }
public EnumModifiers Modifiers { get; set; }
public List<Item> Items;
public Dictionary<string, Item> ItemsByName;
}
/// <summary>
/// Represents a C/C++ enumeration declaration.
/// </summary>
public class Enumeration : Declaration
{
[Flags]
public enum EnumModifiers
{
Anonymous,
Scoped,
Flags
}
/// <summary>
/// Represents a C/C++ enumeration item.
/// </summary>
public class Item
{
public string Name;
public long Value;
public string Expression;
public string Comment;
public bool ExplicitValue = true;
}
public Enumeration()
{
Items = new List<Item>();
ItemsByName = new Dictionary<string, Item>();
BuiltinType = new BuiltinType(PrimitiveType.Int32);
}
public Enumeration AddItem(Item item)
{
Items.Add(item);
ItemsByName[item.Name] = item;
return this;
}
public Enumeration SetFlags()
{
Modifiers |= EnumModifiers.Flags;
return this;
}
public Type Type { get; set; }
public BuiltinType BuiltinType { get; set; }
public EnumModifiers Modifiers { get; set; }
public List<Item> Items;
public Dictionary<string, Item> ItemsByName;
public override T Visit<T>(IDeclVisitor<T> visitor)
{
return visitor.VisitEnumDecl(this);
}
}
}

43
src/Bridge/Field.cs

@ -1,23 +1,30 @@ @@ -1,23 +1,30 @@
namespace Cxxi
{
/// <summary>
/// Represents a field in a C/C++ record declaration.
/// </summary>
public class Field : Declaration
{
public Type Type;
public AccessSpecifier Access;
public uint Offset = 0;
/// <summary>
/// Represents a a C/C++ record field Decl.
/// </summary>
public class Field : Declaration
{
public Type Type { get; set; }
public AccessSpecifier Access { get; set; }
public uint Offset { get; set; }
public Field()
{
}
public Field()
{
Offset = 0;
}
public Field(string name, Type type, AccessSpecifier access)
{
Name = name;
Type = type;
Access = access;
}
}
public Field(string name, Type type, AccessSpecifier access)
{
Name = name;
Type = type;
Access = access;
Offset = 0;
}
public override T Visit<T>(IDeclVisitor<T> visitor)
{
return visitor.VisitFieldDecl(this);
}
}
}

133
src/Bridge/Function.cs

@ -3,53 +3,88 @@ using System.Collections.Generic; @@ -3,53 +3,88 @@ using System.Collections.Generic;
namespace Cxxi
{
public enum CallingConvention
{
Default,
C,
StdCall,
ThisCall,
FastCall
}
public enum ParameterUsage
{
Unknown,
In,
Out,
InOut
}
public class Parameter : Declaration
{
public Parameter()
{
Usage = ParameterUsage.Unknown;
HasDefaultValue = false;
}
public Type Type { get; set; }
public ParameterUsage Usage { get; set; }
public bool HasDefaultValue { get; set; }
}
public class Function : Declaration
{
public Function()
{
Parameters = new List<Parameter>();
CallingConvention = CallingConvention.Default;
IsVariadic = false;
IsInline = false;
}
public Type ReturnType { get; set; }
public List<Parameter> Parameters { get; set; }
public CallingConvention CallingConvention { get; set; }
public bool IsVariadic { get; set; }
public bool IsInline { get; set; }
// The C# name
public string FormattedName { get; set; }
}
public enum CallingConvention
{
Default,
C,
StdCall,
ThisCall,
FastCall,
Unknown
}
public enum ParameterUsage
{
In,
Out,
InOut,
Unknown
}
public class Parameter : Declaration
{
public Parameter()
{
Usage = ParameterUsage.Unknown;
HasDefaultValue = false;
IsConst = false;
}
public Type Type { get; set; }
public ParameterUsage Usage { get; set; }
public bool HasDefaultValue { get; set; }
public bool IsConst { get; set; }
public override T Visit<T>(IDeclVisitor<T> visitor)
{
return visitor.VisitParameterDecl(this);
}
}
public class Function : Declaration
{
public Function()
{
Parameters = new List<Parameter>();
CallingConvention = CallingConvention.Default;
IsVariadic = false;
IsInline = false;
}
public string ToCSharpCallConv()
{
switch (CallingConvention)
{
case CallingConvention.Default:
return "Winapi";
case CallingConvention.C:
return "Cdecl";
case CallingConvention.StdCall:
return "StdCall";
case CallingConvention.ThisCall:
return "ThisCall";
case CallingConvention.FastCall:
return "FastCall";
}
return "Winapi";
}
public Type ReturnType { get; set; }
public List<Parameter> Parameters { get; set; }
public CallingConvention CallingConvention { get; set; }
public bool IsVariadic { get; set; }
public bool IsInline { get; set; }
// Mangled name
public string Mangled { get; set; }
// Transformed name
public string FormattedName { get; set; }
public override T Visit<T>(IDeclVisitor<T> visitor)
{
return visitor.VisitFunctionDecl(this);
}
}
}

204
src/Bridge/Library.cs

@ -1,104 +1,114 @@ @@ -1,104 +1,114 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
namespace Cxxi
{
public enum CppAbi
{
Itanium,
Microsoft,
ARM
}
public enum InlineMethods
{
Present,
Unavailable
}
/// <summary>
/// A module represents a parsed C++ translation unit.
/// </summary>
[DebuggerDisplay("File = {FileName}, Ignored = {Ignore}")]
public class Module : Namespace
{
public Module(string file)
{
Macros = new List<MacroDefine>();
FilePath = file;
Ignore = false;
}
/// Contains the macros present in the unit.
public List<MacroDefine> Macros;
/// If the module should be ignored.
public bool Ignore;
/// Contains the path to the file.
public string FilePath;
/// Contains the name of the file.
public string FileName
{
get { return Path.GetFileName(FilePath); }
}
}
/// <summary>
/// A library contains all the modules.
/// </summary>
public class Library
{
public string Name;
public string Native;
public List<Module> Modules;
public Library(string name, string native)
{
Name = name;
Native = native;
Modules = new List<Module>();
}
/// Finds an existing module or creates a new one given a file path.
public Module FindOrCreateModule(string file)
{
var module = Modules.Find(m => m.FilePath.Equals(file));
if (module == null)
{
module = new Module(file);
Modules.Add(module);
}
return module;
}
/// Finds an existing enum in the library modules.
public Enumeration FindEnum(string name)
{
foreach (var module in Modules)
{
var type = module.FindEnum(name);
if (type != null) return type;
}
return null;
}
/// Finds an existing struct/class in the library modules.
public Class FindClass(string name, bool create = false)
{
foreach (var module in Modules)
{
var type = module.FindClass(name, create);
if (type != null) return type;
}
return null;
}
}
public enum CppAbi
{
Itanium,
Microsoft,
ARM
}
/// <summary>
/// Represents a parsed C++ unit.
/// </summary>
[DebuggerDisplay("File = {FileName}, Ignored = {Ignore}")]
public class TranslationUnit : Namespace
{
public TranslationUnit(string file)
{
ForwardReferences = new List<Declaration>();
Macros = new List<MacroDefinition>();
FilePath = file;
}
/// Forward reference declarations.
public List<Declaration> ForwardReferences;
/// Contains the macros present in the unit.
public List<MacroDefinition> Macros;
/// If the module should be ignored.
public override bool Ignore
{
get { return ExplicityIgnored; }
}
public bool IsSystemHeader { get; set; }
/// Contains the path to the file.
public string FilePath;
/// Contains the name of the file.
public string FileName
{
get { return Path.GetFileName(FilePath); }
}
/// Contains the name of the module.
public string FileNameWithoutExtension
{
get { return Path.GetFileNameWithoutExtension(FileName); }
}
/// Contains the include path.
public string IncludePath;
}
/// <summary>
/// A library contains all the modules.
/// </summary>
public class Library
{
public string Name;
public string Native;
public List<TranslationUnit> TranslationUnits;
public Library(string name, string native)
{
Name = name;
Native = native;
TranslationUnits = new List<TranslationUnit>();
}
/// Finds an existing module or creates a new one given a file path.
public TranslationUnit FindOrCreateModule(string file)
{
var module = TranslationUnits.Find(m => m.FilePath.Equals(file));
if (module == null)
{
module = new TranslationUnit(file);
TranslationUnits.Add(module);
}
return module;
}
/// Finds an existing enum in the library modules.
public Enumeration FindEnum(string name)
{
foreach (var module in TranslationUnits)
{
var type = module.FindEnum(name);
if (type != null) return type;
}
return null;
}
/// Finds an existing struct/class in the library modules.
public Class FindClass(string name, bool create = false)
{
foreach (var module in TranslationUnits)
{
var type = module.FindClass(name, create);
if (type != null) return type;
}
return null;
}
}
}

114
src/Bridge/Method.cs

@ -1,26 +1,94 @@ @@ -1,26 +1,94 @@
using System;
using System.Collections.Generic;
namespace Cxxi
{
/// <summary>
/// Represents a C++ method.
/// </summary>
public class Method : Function
{
public Method()
{
}
public AccessSpecifier Access { get; set; }
public bool IsVirtual { get; set; }
public bool IsStatic { get; set; }
public bool IsConst { get; set; }
public bool IsArtificial { get; set; }
public bool IsConstructor { get; set; }
public bool IsDestructor { get; set; }
public bool IsCopyCtor { get; set; }
}
public enum CXXMethodKind
{
Normal,
Constructor,
Destructor,
Conversion,
Operator,
UsingDirective
}
public enum CXXOperatorKind
{
None,
New,
Delete,
Array_New,
Array_Delete,
Plus,
Minus,
Star,
Slash,
Percent,
Caret,
Amp,
Pipe,
Tilde,
Exclaim,
Equal,
Less,
Greater,
PlusEqual,
MinusEqual,
StarEqual,
SlashEqual,
PercentEqual,
CaretEqual,
AmpEqual,
PipeEqual,
LessLess,
GreaterGreater,
LessLessEqual,
GreaterGreaterEqual,
EqualEqual,
ExclaimEqual,
LessEqual,
GreaterEqual,
AmpAmp,
PipePipe,
PlusPlus,
MinusMinus,
Comma,
ArrowStar,
Arrow,
Call,
Subscript,
Conditional
}
/// <summary>
/// Represents a C++ record method declaration.
/// </summary>
public class Method : Function
{
public Method()
{
}
public AccessSpecifier Access { get; set; }
public bool IsVirtual { get; set; }
public bool IsStatic { get; set; }
public bool IsConst { get; set; }
public bool IsImplicit { get; set; }
public CXXMethodKind Kind;
public CXXOperatorKind OperatorKind;
public bool IsConstructor
{
get { return Kind == CXXMethodKind.Constructor; }
}
public bool IsDestructor
{
get { return Kind == CXXMethodKind.Destructor; }
}
public bool IsDefaultConstructor;
public bool IsCopyConstructor;
public bool IsMoveConstructor;
}
}

271
src/Bridge/Namespace.cs

@ -3,106 +3,173 @@ using System.Collections.Generic; @@ -3,106 +3,173 @@ using System.Collections.Generic;
namespace Cxxi
{
/// <summary>
/// Represents a C++ namespace.
/// </summary>
public class Namespace
{
public string Name { get; set; }
public Namespace Parent { get; set; }
public bool IsAnonymous { get; set; }
public List<Namespace> Namespaces;
public List<Enumeration> Enums;
public List<Function> Functions;
public List<Class> Classes;
public List<Typedef> Typedefs;
public Namespace()
: this(null, String.Empty)
{
}
public Namespace(Namespace parent, string name, bool isAnonymous = false)
{
Name = name;
Parent = parent;
IsAnonymous = isAnonymous;
Namespaces = new List<Namespace>();
Enums = new List<Enumeration>();
Functions = new List<Function>();
Classes = new List<Class>();
Typedefs = new List<Typedef>();
}
public Namespace FindNamespace(string name)
{
return Namespaces.Find(e => e.Name.Equals(name));
}
public Enumeration FindEnum(string name)
{
return Enums.Find(e => e.Name.Equals(name));
}
public Function FindFunction(string name)
{
return Functions.Find(e => e.Name.Equals(name));
}
public Class FindClass(string name, bool create = false)
{
Class @class = Classes.Find(e => e.Name.Equals(name));
if (@class == null && create)
{
@class = new Class();
@class.Name = name;
Classes.Add(@class);
}
return @class;
}
public Typedef FindTypedef(string name)
{
return Typedefs.Find(e => e.Name.Equals(name));
}
public T FindType<T>(string name) where T : Declaration
{
var type = FindEnum(name)
?? FindFunction(name)
?? (Declaration)FindClass(name)
?? FindTypedef(name);
return type as T;
}
public Enumeration FindEnumWithItem(string name)
{
return Enums.Find(e => e.ItemsByName.ContainsKey(name));
}
public bool HasDeclarations
{
get
{
Predicate<Declaration> pred = (t => !t.Ignore);
return Enums.Exists(pred) || HasFunctions
|| Classes.Exists(pred) || Namespaces.Exists(n => n.HasDeclarations);
}
}
public bool HasFunctions
{
get
{
Predicate<Declaration> pred = (t => !t.Ignore);
return Functions.Exists(pred) || Namespaces.Exists(n => n.HasFunctions);
}
}
}
/// <summary>
/// Represents a C++ namespace.
/// </summary>
public class Namespace : Declaration
{
public Namespace Parent { get; set; }
public bool IsAnonymous { get; set; }
public List<Namespace> Namespaces;
public List<Enumeration> Enums;
public List<Function> Functions;
public List<Class> Classes;
public List<Template> Templates;
public List<TypedefDecl> Typedefs;
// Translation unit the declaration is contained in.
public TranslationUnit TranslationUnit
{
get
{
if (this is TranslationUnit)
return this as TranslationUnit;
else
return Parent.TranslationUnit;
}
}
/// If the namespace should be ignored.
public override bool Ignore
{
get { return ExplicityIgnored || Parent.Ignore; }
}
public Namespace()
: this(null, String.Empty)
{
}
public Namespace(Namespace parent, string name, bool isAnonymous = false)
{
Name = name;
Parent = parent;
IsAnonymous = isAnonymous;
Namespaces = new List<Namespace>();
Enums = new List<Enumeration>();
Functions = new List<Function>();
Classes = new List<Class>();
Templates = new List<Template>();
Typedefs = new List<TypedefDecl>();
}
public Namespace FindNamespace(string name)
{
return Namespaces.Find(e => e.Name.Equals(name));
}
public Namespace FindCreateNamespace(string name, Namespace parent)
{
var @namespace = FindNamespace(name);
if (@namespace == null)
{
@namespace = new Namespace(parent, name);
Namespaces.Add(@namespace);
}
return @namespace;
}
public Enumeration FindEnum(string name, bool createDecl = false)
{
var @enum = Enums.Find(e => e.Name.Equals(name));
if (@enum == null && createDecl)
{
@enum = new Enumeration() { Name = name, Namespace = this };
Enums.Add(@enum);
}
return @enum;
}
public Function FindFunction(string name, bool createDecl = false)
{
var function = Functions.Find(e => e.Name.Equals(name));
if (function == null && createDecl)
{
function = new Function() { Name = name, Namespace = this };
Functions.Add(function);
}
return function;
}
public Class FindClass(string name, bool createDecl = false)
{
var @class = Classes.Find(e => e.Name.Equals(name));
if (@class == null && createDecl)
{
@class = new Class {Name = name, Namespace = this};
Classes.Add(@class);
}
return @class;
}
public ClassTemplate FindClassTemplate(string name)
{
return null;
}
public TypedefDecl FindTypedef(string name, bool createDecl = false)
{
var typedef = Typedefs.Find(e => e.Name.Equals(name));
if (typedef == null && createDecl)
{
typedef = new TypedefDecl { Name = name, Namespace = this };
Typedefs.Add(typedef);
}
return typedef;
}
public T FindType<T>(string name) where T : Declaration
{
var type = FindEnum(name)
?? FindFunction(name)
?? (Declaration)FindClass(name)
?? FindTypedef(name);
return type as T;
}
public Enumeration FindEnumWithItem(string name)
{
return Enums.Find(e => e.ItemsByName.ContainsKey(name));
}
public bool HasDeclarations
{
get
{
Predicate<Declaration> pred = (t => !t.Ignore);
return Enums.Exists(pred) || HasFunctions
|| Classes.Exists(pred) || Namespaces.Exists(n => n.HasDeclarations);
}
}
public bool HasFunctions
{
get
{
Predicate<Declaration> pred = (t => !t.Ignore);
return Functions.Exists(pred) || Namespaces.Exists(n => n.HasFunctions);
}
}
public bool IsRoot { get { return Parent == null; } }
public override T Visit<T>(IDeclVisitor<T> visitor)
{
return default(T);
//visitor.VisitNamespace(this);
}
}
}

63
src/Bridge/Property.cs

@ -3,40 +3,39 @@ using System.Collections.Generic; @@ -3,40 +3,39 @@ using System.Collections.Generic;
namespace Cxxi
{
/// <summary>
/// Represents a C++ property.
/// </summary>
public class Property
{
/// <summary>
/// Represents a C++ property.
/// </summary>
public class Property
{
public Property(string name, Declaration type)
{
Name = name;
Type = type;
}
public Property(string name, Declaration type)
{
Name = name;
Type = type;
}
public string Name
{
get;
set;
}
public string Name
{
get;
set;
}
public Declaration Type
{
get;
set;
}
public Declaration Type
{
get;
set;
}
public Method GetMethod
{
get;
set;
}
public Method GetMethod
{
get;
set;
}
public Method SetMethod
{
get;
set;
}
}
public Method SetMethod
{
get;
set;
}
}
}

57
src/Bridge/Template.cs

@ -0,0 +1,57 @@ @@ -0,0 +1,57 @@
using System.Collections.Generic;
namespace Cxxi
{
public struct TemplateParameter
{
public string Name;
}
public abstract class Template : Declaration
{
protected Template(Declaration decl)
{
TemplatedDecl = decl;
}
public Declaration TemplatedDecl;
public List<TemplateParameter> Parameters;
}
public class ClassTemplate : Template
{
public ClassTemplate(Declaration decl)
: base(decl)
{
}
public Class TemplatedClass
{
get { return TemplatedDecl as Class; }
}
public override T Visit<T>(IDeclVisitor<T> visitor)
{
return visitor.VisitClassTemplateDecl(this);
}
}
public class FunctionTemplate : Template
{
public FunctionTemplate(Declaration decl)
: base(decl)
{
}
public Function TemplatedFunction
{
get { return TemplatedDecl as Function; }
}
public override T Visit<T>(IDeclVisitor<T> visitor)
{
return visitor.VisitFunctionTemplateDecl(this);
}
}
}

765
src/Bridge/Type.cs

@ -1,378 +1,395 @@ @@ -1,378 +1,395 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
namespace Cxxi
{
public interface TypeTransform
{
void TransformType(Type type);
void TransformTagType(TagType tag);
void TransformArrayType(ArrayType array);
void TransformFunctionType(FunctionType function);
void TransformPointerType(PointerType pointer);
void TransformBuiltinType(BuiltinType builtin);
void TransformTypedefType (TypedefType typedef);
void TransformDeclaration(Declaration declaration);
}
/// <summary>
/// Represents a C++ type reference.
/// </summary>
public abstract class Type
{
public Type()
{
}
public bool IsPrimitiveType(PrimitiveType primitive)
{
var builtin = this as BuiltinType;
if (builtin != null)
return builtin.Type == primitive;
return false;
}
public bool IsPointerToPrimitiveType(PrimitiveType primitive)
{
var ptr = this as PointerType;
if (ptr == null)
return false;
return ptr.Pointee.IsPrimitiveType(primitive);
}
public bool IsPointerTo<T>(out T type) where T : Type
{
var ptr = this as PointerType;
if (ptr == null)
{
type = null;
return false;
}
type = ptr.Pointee as T;
return type != null;
}
public virtual void Transform(TypeTransform transform)
{
transform.TransformType(this);
}
// Converts the type to a C# type.
public abstract string ToCSharp();
public override string ToString()
{
return ToCSharp();
}
}
/// <summary>
/// Represents a C++ tag type reference.
/// </summary>
public class TagType : Type
{
public TagType()
{
}
public Declaration Declaration;
public override string ToCSharp()
{
if (Declaration == null)
return string.Empty;
return Declaration.Name;
}
public override void Transform(TypeTransform transform)
{
transform.TransformTagType(this);
}
}
/// <summary>
/// Represents an C/C++ array type.
/// </summary>
public class ArrayType : Type
{
public enum ArraySize
{
Constant,
Variable
}
public ArrayType()
{
}
// Type of the array elements.
public Type Type;
// Size type of array.
public ArraySize SizeType;
// In case of a constant size array.
public long Size;
public override string ToCSharp()
{
// C# only supports fixed arrays in unsafe sections
// and they are constrained to a set of built-in types.
return string.Format("{0}[]", Type);
}
public override void Transform(TypeTransform transform)
{
Type.Transform(transform);
}
}
/// <summary>
/// Represents an C/C++ function type.
/// </summary>
public class FunctionType : Type
{
// Return type of the function.
public Type ReturnType;
// Argument types.
public List<Type> Arguments;
public FunctionType()
{
Arguments = new List<Type>();
}
public override string ToCSharp()
{
string args = string.Empty;
if (Arguments.Count > 0)
args = ToArgumentString();
if (ReturnType.IsPrimitiveType(PrimitiveType.Void))
{
if (!string.IsNullOrEmpty(args))
args = string.Format("<{0}>", args);
return string.Format("Action{0}", args);
}
if (!string.IsNullOrEmpty(args))
args = string.Format(", {0}", args);
return string.Format("Func<{0}{1}>",
ReturnType.ToCSharp(), args);
}
public string ToArgumentString()
{
var s = string.Empty;
for (int i = 0; i < Arguments.Count; ++i)
{
var arg = Arguments[i];
s += arg.ToCSharp();
if (i < Arguments.Count - 1)
s += ", ";
}
return s;
}
public string ToDelegateString()
{
return string.Format("delegate {0} {{0}}({1})",
ReturnType.ToCSharp(), ToArgumentString());
}
public override void Transform(TypeTransform transform)
{
ReturnType.Transform(transform);
}
}
/// <summary>
/// Represents a C++ pointer/reference type.
/// </summary>
public class PointerType : Type
{
public PointerType()
{
}
/// <summary>
/// Represents the modifiers on a C++ type reference.
/// </summary>
public enum TypeModifier
{
Value,
Pointer,
// L-value references
LVReference,
// R-value references
RVReference
}
static string ConvertModifierToString(TypeModifier modifier)
{
switch (modifier)
{
case TypeModifier.Value: return string.Empty;
case TypeModifier.Pointer:
case TypeModifier.LVReference:
case TypeModifier.RVReference: return "*";
}
return string.Empty;
}
public Type Pointee;
public TypeModifier Modifier;
public override string ToCSharp()
{
if (Pointee is FunctionType)
{
var function = Pointee as FunctionType;
return function.ToCSharp();
}
if (Pointee is TagType)
return Pointee.ToCSharp();
return "IntPtr";
//return string.Format("{0}{1}",
// Pointee.ToCSharp(), ConvertModifierToString(Modifier));
}
public override void Transform(TypeTransform transform)
{
Pointee.Transform(transform);
}
}
public class TypedefType : Type
{
public TypedefType()
{
}
public Declaration Declaration;
public override void Transform(TypeTransform transform)
{
transform.TransformTypedefType(this);
}
public override string ToCSharp()
{
return Declaration.Name;
}
}
#region Primitives
/// <summary>
/// Represents the C++ built-in types.
/// </summary>
public enum PrimitiveType
{
Null,
Void,
Bool,
WideChar,
Int8,
UInt8,
Int16,
UInt16,
Int32,
UInt32,
Int64,
UInt64,
Float,
Double
}
/// <summary>
/// Represents an instance of a C++ built-in type.
/// </summary>
public class BuiltinType : Type
{
public BuiltinType()
{
}
public BuiltinType(PrimitiveType type)
{
Type = type;
}
// Primitive type of built-in type.
public PrimitiveType Type;
public override string ToCSharp()
{
return Type.ConvertToTypeName();
}
public override void Transform(TypeTransform transform)
{
}
}
public static class PrimitiveTypeExtensions
{
public static System.Type ConvertToType(this PrimitiveType Primitive)
{
switch (Primitive)
{
case PrimitiveType.Bool: return typeof(bool);
case PrimitiveType.Void: return typeof(void);
case PrimitiveType.WideChar: return typeof(char);
case PrimitiveType.Int8: return typeof(sbyte);
case PrimitiveType.UInt8: return typeof(byte);
case PrimitiveType.Int16: return typeof(short);
case PrimitiveType.UInt16: return typeof(ushort);
case PrimitiveType.Int32: return typeof(int);
case PrimitiveType.UInt32: return typeof(uint);
case PrimitiveType.Int64: return typeof(long);
case PrimitiveType.UInt64: return typeof(ulong);
case PrimitiveType.Float: return typeof(float);
case PrimitiveType.Double: return typeof(double);
}
return typeof(int);
}
public static string ConvertToTypeName(this PrimitiveType Primitive)
{
switch (Primitive)
{
case PrimitiveType.Bool: return "bool";
case PrimitiveType.Void: return "void";
case PrimitiveType.WideChar: return "char";
case PrimitiveType.Int8: return "sbyte";
case PrimitiveType.UInt8: return "byte";
case PrimitiveType.Int16: return "short";
case PrimitiveType.UInt16: return "ushort";
case PrimitiveType.Int32: return "int";
case PrimitiveType.UInt32: return "uint";
case PrimitiveType.Int64: return "long";
case PrimitiveType.UInt64: return "ulong";
case PrimitiveType.Float: return "float";
case PrimitiveType.Double: return "double";
}
return String.Empty;
}
}
#endregion
/// <summary>
/// Represents a C++ type reference.
/// </summary>
public abstract class Type
{
public static ITypeVisitor<string> TypePrinter;
protected Type()
{
}
public bool IsPrimitiveType(PrimitiveType primitive)
{
var builtin = this as BuiltinType;
if (builtin != null)
return builtin.Type == primitive;
return false;
}
public bool IsEnumType()
{
var tag = this as TagType;
if (tag == null)
return false;
return tag.Declaration is Enumeration;
}
public bool IsPointerToPrimitiveType(PrimitiveType primitive)
{
var ptr = this as PointerType;
if (ptr == null)
return false;
return ptr.Pointee.IsPrimitiveType(primitive);
}
public bool IsPointerTo<T>(out T type) where T : Type
{
var ptr = this as PointerType;
if (ptr == null)
{
type = null;
return false;
}
type = ptr.Pointee as T;
return type != null;
}
public bool IsTagDecl<T>(out T decl) where T : Declaration
{
var tag = this as TagType;
if (tag == null)
{
decl = null;
return false;
}
decl = tag.Declaration as T;
return decl != null;
}
public abstract T Visit<T>(ITypeVisitor<T> visitor, TypeQualifiers quals
= new TypeQualifiers());
public override string ToString()
{
return Visit(TypePrinter);
}
}
public struct TypeQualifiers
{
public bool IsConst;
public bool IsVolatile;
public bool IsRestrict;
}
/// <summary>
/// Represents a C++ tag type reference.
/// </summary>
public class TagType : Type
{
public TagType()
{
}
public Declaration Declaration;
public override T Visit<T>(ITypeVisitor<T> visitor, TypeQualifiers quals)
{
return visitor.VisitTagType(this, quals);
}
}
/// <summary>
/// Represents an C/C++ array type.
/// </summary>
public class ArrayType : Type
{
public enum ArraySize
{
Constant,
Variable
}
public ArrayType()
{
}
// Type of the array elements.
public Type Type;
// Size type of array.
public ArraySize SizeType;
// In case of a constant size array.
public long Size;
public override T Visit<T>(ITypeVisitor<T> visitor, TypeQualifiers quals)
{
return visitor.VisitArrayType(this, quals);
}
}
/// <summary>
/// Represents an C/C++ function type.
/// </summary>
public class FunctionType : Type
{
// Return type of the function.
public Type ReturnType;
// Argument types.
public List<Parameter> Arguments;
public FunctionType()
{
Arguments = new List<Parameter>();
}
public override T Visit<T>(ITypeVisitor<T> visitor, TypeQualifiers quals)
{
return visitor.VisitFunctionType(this, quals);
}
}
/// <summary>
/// Represents a C++ pointer/reference type.
/// </summary>
public class PointerType : Type
{
public PointerType()
{
}
/// <summary>
/// Represents the modifiers on a C++ type reference.
/// </summary>
public enum TypeModifier
{
Value,
Pointer,
// L-value references
LVReference,
// R-value references
RVReference
}
static string ConvertModifierToString(TypeModifier modifier)
{
switch (modifier)
{
case TypeModifier.Value: return string.Empty;
case TypeModifier.Pointer:
case TypeModifier.LVReference:
case TypeModifier.RVReference: return "*";
}
return string.Empty;
}
public bool IsReference
{
get
{
return Modifier == TypeModifier.LVReference
|| Modifier == TypeModifier.RVReference;
}
}
public Type Pointee;
public TypeModifier Modifier;
public override T Visit<T>(ITypeVisitor<T> visitor, TypeQualifiers quals)
{
return visitor.VisitPointerType(this, quals);
}
}
/// <summary>
/// Represents a C++ member function pointer type.
/// </summary>
public class MemberPointerType : Type
{
public MemberPointerType()
{
}
public Type Pointee;
public override T Visit<T>(ITypeVisitor<T> visitor, TypeQualifiers quals)
{
return visitor.VisitMemberPointerType(this, quals);
}
}
/// <summary>
/// Represents a C/C++ typedef type.
/// </summary>
public class TypedefType : Type
{
public TypedefType()
{
}
public TypedefDecl Declaration;
public override T Visit<T>(ITypeVisitor<T> visitor, TypeQualifiers quals)
{
return visitor.VisitTypedefType(this, quals);
}
}
/// <summary>
/// Represents a template argument within a class template specialization.
/// </summary>
public struct TemplateArgument
{
/// The kind of template argument we're storing.
public enum ArgumentKind
{
/// The template argument is a type.
Type,
/// The template argument is a declaration that was provided for a
/// pointer. reference, or pointer to member non-type template
/// parameter.
Declaration,
/// The template argument is a null pointer or null pointer to member
/// that was provided for a non-type template parameter.
NullPtr,
/// The template argument is an integral value that was provided for
/// an integral non-type template parameter.
Integral,
/// The template argument is a template name that was provided for a
/// template template parameter.
Template,
/// The template argument is a pack expansion of a template name that
/// was provided for a template template parameter.
TemplateExpansion,
/// The template argument is a value- or type-dependent expression.
Expression,
/// The template argument is actually a parameter pack.
Pack
}
public ArgumentKind Kind;
public Type Type;
public Declaration Declaration;
public long Integral;
}
/// <summary>
/// Represents a C++ template specialization type.
/// </summary>
public class TemplateSpecializationType : Type
{
public TemplateSpecializationType()
{
Arguments = new List<TemplateArgument>();
}
public List<TemplateArgument> Arguments;
public Template Template;
public override T Visit<T>(ITypeVisitor<T> visitor,
TypeQualifiers quals = new TypeQualifiers())
{
return visitor.VisitTemplateSpecializationType(this, quals);
}
}
/// <summary>
/// Represents a C++ template parameter type.
/// </summary>
public class TemplateParameterType : Type
{
public TemplateParameterType()
{
}
public TemplateParameter Parameter;
public Template Template;
public override T Visit<T>(ITypeVisitor<T> visitor,
TypeQualifiers quals = new TypeQualifiers())
{
//return visitor.VisitTemplateParameterType(this, quals);
return default(T);
}
}
#region Primitives
/// <summary>
/// Represents the C++ built-in types.
/// </summary>
public enum PrimitiveType
{
Null,
Void,
Bool,
WideChar,
Int8,
Char = Int8,
UInt8,
UChar = UInt8,
Int16,
UInt16,
Int32,
UInt32,
Int64,
UInt64,
Float,
Double
}
/// <summary>
/// Represents an instance of a C++ built-in type.
/// </summary>
public class BuiltinType : Type
{
public BuiltinType()
{
}
public BuiltinType(PrimitiveType type)
{
Type = type;
}
// Primitive type of built-in type.
public PrimitiveType Type;
public override T Visit<T>(ITypeVisitor<T> visitor, TypeQualifiers quals)
{
return visitor.VisitBuiltinType(this, quals);
}
}
#endregion
public interface ITypeVisitor<out T>
{
T VisitTagType(TagType tag, TypeQualifiers quals);
T VisitArrayType(ArrayType array, TypeQualifiers quals);
T VisitFunctionType(FunctionType function, TypeQualifiers quals);
T VisitPointerType(PointerType pointer, TypeQualifiers quals);
T VisitMemberPointerType(MemberPointerType member, TypeQualifiers quals);
T VisitBuiltinType(BuiltinType builtin, TypeQualifiers quals);
T VisitTypedefType(TypedefType typedef, TypeQualifiers quals);
T VisitTemplateSpecializationType(TemplateSpecializationType template,
TypeQualifiers quals);
T VisitDeclaration(Declaration decl, TypeQualifiers quals);
}
}

6
src/Generator.Tests/App.config

@ -0,0 +1,6 @@ @@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
</configuration>

67
src/Generator.Tests/Generator.Tests.csproj

@ -0,0 +1,67 @@ @@ -0,0 +1,67 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{3EC927F3-5F8D-4D5D-B230-901ED2BB5D32}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Generator.Tests</RootNamespace>
<AssemblyName>Generator.Tests</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<StartupObject />
</PropertyGroup>
<ItemGroup>
<None Include="App.config" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<Compile Include="TestCLITypePrinter.cs" />
</ItemGroup>
<ItemGroup>
<Reference Include="nunit.framework">
<HintPath>..\..\build\packages\NUnit.2.6.2\lib\nunit.framework.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Bridge\Bridge.csproj">
<Project>{6beb8fa2-97aa-40b7-ab92-42f6eddc4490}</Project>
<Name>Bridge</Name>
</ProjectReference>
<ProjectReference Include="..\Generator\Generator.csproj">
<Project>{73499B8E-A6A4-42FF-AB8A-754CE2780777}</Project>
<Name>Generator</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

21
src/Generator.Tests/TestCLITypePrinter.cs

@ -0,0 +1,21 @@ @@ -0,0 +1,21 @@
using Cxxi.Generators.CLI;
using NUnit.Framework;
namespace Generator.Tests
{
[TestFixture]
public class CLITypePrinterTest
{
private readonly CLITypePrinter printer;
CLITypePrinterTest()
{
//printer = new CLITypePrinter();
}
[Test]
public void Test()
{
}
}
}

4
src/Generator.Tests/packages.config

@ -0,0 +1,4 @@ @@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="NUnit" version="2.6.2" targetFramework="net45" />
</packages>

224
src/Generator/CodeGenerator.cs

@ -0,0 +1,224 @@ @@ -0,0 +1,224 @@
using System.Reflection;
using Cxxi.Generators;
using Cxxi.Passes;
using Mono.Options;
using System;
using System.Collections.Generic;
using System.IO;
namespace Cxxi
{
class CodeGenerator
{
private readonly Options options;
private Library library;
private readonly ILibrary transform;
public CodeGenerator(Options options, ILibrary transform)
{
this.options = options;
this.transform = transform;
}
public void ParseCode()
{
library = new Library(options.OutputNamespace, options.LibraryName);
var parserOptions = new ParserOptions
{
Library = library,
Verbose = false,
IncludeDirs = options.IncludeDirs
};
Console.WriteLine("Parsing code...");
foreach (var file in options.Headers)
{
var path = string.Empty;
try
{
path = Path.GetFullPath(file);
}
catch (ArgumentException)
{
Console.WriteLine("Invalid path '" + file + "'.");
continue;
}
var module = new TranslationUnit(path);
parserOptions.FileName = path;
if (!ClangParser.Parse(parserOptions))
{
Console.WriteLine(" Could not parse '" + file + "'.");
continue;
}
Console.WriteLine(" Parsed '" + file + "'.");
}
}
public void ProcessCode()
{
if (transform != null)
transform.Preprocess(new LibraryHelpers(library));
var passes = new PassBuilder();
//passes.AddPass(new Transform());
//passes.AddPass(new Preprocess());
if (transform != null)
transform.SetupPasses(passes);
var preprocess = new Preprocess();
preprocess.ProcessLibrary(library);
var transformer = new Transform() { Options = options, Passes = passes };
transformer.TransformLibrary(library);
if (transform != null)
transform.Postprocess(new LibraryHelpers(library));
}
public void GenerateCode()
{
if (library.TranslationUnits.Count <= 0)
return;
Console.WriteLine("Generating wrapper code...");
var gen = new Generator(options, library, transform);
gen.Generate();
}
}
public class Options
{
public Options()
{
Defines = new List<string>();
IncludeDirs = new List<string>();
Headers = new List<string>();
Assembly = string.Empty;
}
public bool Verbose = false;
public bool ShowHelpText = false;
public bool OutputDebug = false;
public string OutputNamespace;
public string OutputDir;
public string LibraryName;
public List<string> Defines;
public List<string> IncludeDirs;
public List<string> Headers;
public string Template;
public string Assembly;
}
class Program
{
static void ShowHelp(OptionSet options)
{
var module = System.Diagnostics.Process.GetCurrentProcess().MainModule;
var exeName = Path.GetFileName(module.FileName);
Console.WriteLine("Usage: " + exeName + " [options]+ headers");
Console.WriteLine("Generates .NET bindings from C/C++ header files.");
Console.WriteLine();
Console.WriteLine("Options:");
options.WriteOptionDescriptions(Console.Out);
}
static bool ParseCommandLineOptions(String[] args, Options options)
{
var set = new OptionSet()
{
// Parser options
{ "D|defines=", v => options.Defines.Add(v) },
{ "I|include=", v => options.IncludeDirs.Add(v) },
// Generator options
{ "ns|namespace=", v => options.OutputNamespace = v },
{ "o|outdir=", v => options.OutputDir = v },
{ "debug", v => options.OutputDebug = true },
{ "lib|library=", v => options.LibraryName = v },
{ "t|template=", v => options.Template = v },
{ "a|assembly=", v => options.Assembly = v },
// Misc. options
{ "v|verbose", v => { options.Verbose = true; } },
{ "h|?|help", v => options.ShowHelpText = v != null },
};
if (args.Length == 0 || options.ShowHelpText)
{
ShowHelp(set);
return false;
}
try
{
options.Headers = set.Parse(args);
}
catch (OptionException)
{
Console.WriteLine("Error parsing the command line.");
ShowHelp(set);
return false;
}
return true;
}
static bool ParseLibraryAssembly(string path, out ILibrary library)
{
library = null;
if (string.IsNullOrWhiteSpace(path))
{
Console.WriteLine("Error: no assembly provided");
return false;
}
try
{
var fullPath = Path.GetFullPath(path);
var assembly = Assembly.LoadFile(fullPath);
var types = assembly.FindDerivedTypes(typeof(ILibrary));
foreach (var type in types)
{
var attrs = type.GetCustomAttributes<LibraryTransformAttribute>();
if (attrs == null) continue;
Console.WriteLine("Found library transform: {0}", type.Name);
library = (ILibrary)Activator.CreateInstance(type);
}
}
catch (Exception ex)
{
Console.WriteLine("Error: assembly '{0}' could not be loaded", path);
return false;
}
return true;
}
static void Main(String[] args)
{
var options = new Options();
if (!ParseCommandLineOptions(args, options))
return;
ILibrary library = null;
if (!ParseLibraryAssembly(options.Assembly, out library))
return;
var codeGenerator = new CodeGenerator(options, library);
codeGenerator.ParseCode();
codeGenerator.ProcessCode();
codeGenerator.GenerateCode();
}
}
}

63
src/Generator/Filter.cs

@ -3,34 +3,37 @@ using System.Linq; @@ -3,34 +3,37 @@ using System.Linq;
using System.Xml.Linq;
using System.Collections.Generic;
public enum FilterMode {
Include,
Exclude,
External
}
public enum ImplementationType {
@class,
@struct
}
public struct Filter {
public string TypeName { get; set; }
public FilterMode Mode { get; set; }
public ImplementationType ImplType { get; set; }
public static Dictionary<string, Filter> Load (XDocument doc, out FilterMode @default)
{
string value;
@default = (value = (string)doc.Root.Attribute ("default")) != null ? (FilterMode)Enum.Parse (typeof (FilterMode), value) : FilterMode.Include;
var rules = from rule in doc.Root.Elements ()
let mode = (FilterMode)Enum.Parse (typeof (FilterMode), rule.Name.LocalName)
let impl = (value = (string)rule.Attribute ("implementation")) != null ? (ImplementationType)Enum.Parse (typeof (ImplementationType), value) : ImplementationType.@class
select new Filter { TypeName = rule.Value, Mode = mode, ImplType = impl };
return rules.ToDictionary<Filter,string> (r => r.TypeName);
}
namespace Cxxi
{
public enum FilterMode {
Include,
Exclude,
External
}
public enum ImplementationType {
@class,
@struct
}
public struct Filter {
public string TypeName { get; set; }
public FilterMode Mode { get; set; }
public ImplementationType ImplType { get; set; }
public static Dictionary<string, Filter> Load (XDocument doc, out FilterMode @default)
{
string value;
@default = (value = (string)doc.Root.Attribute ("default")) != null ? (FilterMode)System.Enum.Parse (typeof (FilterMode), value) : FilterMode.Include;
var rules = from rule in doc.Root.Elements ()
let mode = (FilterMode)System.Enum.Parse (typeof (FilterMode), rule.Name.LocalName)
let impl = (value = (string)rule.Attribute ("implementation")) != null ? (ImplementationType)System.Enum.Parse (typeof (ImplementationType), value) : ImplementationType.@class
select new Filter { TypeName = rule.Value, Mode = mode, ImplType = impl };
return rules.ToDictionary<Filter,string> (r => r.TypeName);
}
}
}

271
src/Generator/Generator.cs

@ -1,271 +0,0 @@ @@ -1,271 +0,0 @@
using Cxxi.Templates;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
namespace Cxxi
{
public partial class Generator
{
public List<ModuleTransform> Transformations { get; set; }
Library Library;
Options Options;
public Generator(Library library, Options options)
{
Transformations = new List<ModuleTransform>();
Library = library;
Options = options;
}
public void Process()
{
TransformModule();
ProcessModules();
}
// Generates the binding code.
public void Generate()
{
GenerateModules();
}
int UniqueName = 0;
void CleanupText(ref string debugText)
{
// Strip off newlines from the debug text.
if (String.IsNullOrWhiteSpace(debugText))
debugText = String.Empty;
// TODO: Make this transformation in the output.
debugText = Regex.Replace(debugText, " ( )+", " ");
debugText = Regex.Replace(debugText, "\n", "");
}
void ProcessDeclaration(Declaration decl)
{
// If after all the transformations the type still does
// not have a name, then generate one.
if (string.IsNullOrWhiteSpace(decl.Name))
decl.Name = string.Format("Unnamed{0}", UniqueName++);
CleanupText(ref decl.DebugText);
}
void ProcessDeclarations<T>(List<T> decls) where T : Declaration
{
foreach (T decl in decls)
ProcessDeclaration(decl);
}
void ProcessClasses(List<Class> classes)
{
ProcessDeclarations(classes);
foreach (var @class in classes)
ProcessDeclarations(@class.Fields);
}
void ProcessTypedefs(Namespace @namespace, List<Typedef> typedefs)
{
ProcessDeclarations(typedefs);
foreach (var typedef in typedefs)
{
var @class = @namespace.FindClass(typedef.Name);
// Clang will walk the typedef'd tag type and the typedef decl,
// so we ignore the class and process just the typedef.
if (@class != null)
typedef.Ignore = true;
}
}
void ProcessFunctions(List<Function> Functions)
{
ProcessDeclarations(Functions);
foreach (var function in Functions)
{
if (function.ReturnType == null)
{
// Ignore and warn about unknown types.
function.Ignore = true;
var s = "Function '{0}' was ignored due to unknown return type...";
Console.WriteLine(String.Format(s, function.Name));
}
foreach (var param in function.Parameters)
{
ProcessDeclaration(param);
}
}
}
void ProcessModules()
{
if (string.IsNullOrEmpty(Library.Name))
Library.Name = "";
// Process everything in the global namespace for now.
foreach (var module in Library.Modules)
{
ProcessNamespace(module);
}
}
void ProcessNamespace(Namespace @namespace)
{
ProcessDeclarations(@namespace.Enums);
ProcessFunctions(@namespace.Functions);
ProcessClasses(@namespace.Classes);
ProcessTypedefs(@namespace, @namespace.Typedefs);
}
void TransformModule()
{
if (string.IsNullOrEmpty(Library.Name))
Library.Name = string.Empty;
// Process everything in the global namespace for now.
foreach (var module in Library.Modules)
{
foreach (Enumeration @enum in module.Enums)
TransformEnum(@enum);
foreach (Function function in module.Functions)
TransformFunction(function);
foreach (Class @class in module.Classes)
TransformClass(@class);
foreach (Typedef typedef in module.Typedefs)
TransformTypedef(typedef);
}
}
void TransformDeclaration(Declaration decl)
{
foreach (var transform in Transformations)
transform.ProcessDeclaration(decl);
}
void TransformTypedef(Typedef typedef)
{
foreach (var transform in Transformations)
transform.ProcessDeclaration(typedef);
}
void TransformClass(Class @class)
{
TransformDeclaration(@class);
foreach (var field in @class.Fields)
TransformDeclaration(field);
}
void TransformFunction(Function function)
{
TransformDeclaration(function);
foreach (var param in function.Parameters)
TransformDeclaration(param);
}
void TransformEnum(Enumeration @enum)
{
TransformDeclaration(@enum);
foreach (var transform in Transformations)
{
foreach (var item in @enum.Items)
transform.ProcessEnumItem(item);
}
// If the enumeration only has power of two values, assume it's
// a flags enum.
bool isFlags = true;
bool hasBigRange = false;
foreach (var item in @enum.Items)
{
if (item.Name.Length >= 1 && Char.IsDigit(item.Name[0]))
item.Name = String.Format("_{0}", item.Name);
long value = item.Value;
if (value >= 4)
hasBigRange = true;
if (value <= 1 || value.IsPowerOfTwo())
continue;
isFlags = false;
}
// Only apply this heuristic if there are enough values to have a
// reasonable chance that it really is a bitfield.
if (isFlags && hasBigRange)
{
@enum.Modifiers |= Enumeration.EnumModifiers.Flags;
}
// If we still do not have a valid name, then try to guess one
// based on the enum value names.
if (!String.IsNullOrWhiteSpace(@enum.Name))
return;
var names = new List<string>();
foreach (var item in @enum.Items)
names.Add(item.Name);
var prefix = names.ToArray().CommonPrefix();
// Try a simple heuristic to make sure we end up with a valid name.
if (prefix.Length >= 3)
{
prefix = prefix.Trim().Trim(new char[] { '_' });
@enum.Name = prefix;
}
}
void GenerateModules()
{
// Process everything in the global namespace for now.
foreach (var module in Library.Modules)
{
if (module.Ignore || !module.HasDeclarations)
continue;
// Generate the code from templates.
var template = new CSharpModule();
template.Library = Library;
template.Options = Options;
template.Module = module;
if (!Directory.Exists(Options.OutputDir))
Directory.CreateDirectory(Options.OutputDir);
var file = Path.GetFileNameWithoutExtension(module.FileName) + ".cs";
var path = Path.Combine(Options.OutputDir, file);
// Normalize path.
path = Path.GetFullPath(path);
string code = template.TransformText();
Console.WriteLine(" Generated '" + file + "'.");
File.WriteAllText(path, code);
}
}
}
}

100
src/Generator/Generator.csproj

@ -10,75 +10,115 @@ @@ -10,75 +10,115 @@
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Cxxi</RootNamespace>
<AssemblyName>Generator</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<TargetFrameworkProfile>
</TargetFrameworkProfile>
<FileAlignment>512</FileAlignment>
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
<UpdateEnabled>false</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
<UpdateInterval>7</UpdateInterval>
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
<UpdatePeriodically>false</UpdatePeriodically>
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<IsWebBootstrapper>false</IsWebBootstrapper>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<PlatformTarget>x86</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>$(SolutionDir)bin\</OutputPath>
<OutputPath>..\..\build\bin\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<UseVSHostingProcess>true</UseVSHostingProcess>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<PlatformTarget>x86</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<OutputPath>..\..\build\bin\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup>
<StartupObject>Program</StartupObject>
<StartupObject>
</StartupObject>
</PropertyGroup>
<ItemGroup>
<Reference Include="Parser_d">
<HintPath>..\..\bin\Parser_d.dll</HintPath>
<HintPath>..\..\build\bin\Parser_d.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Libraries\Clang.cs" />
<Compile Include="Filter.cs" />
<Compile Include="Generator.cs" />
<Compile Include="Glob.cs" />
<Compile Include="Helpers.cs" />
<Compile Include="Options.cs" />
<Compile Include="Program.cs" />
<Compile Include="Generators\Generator.cs" />
<Compile Include="Types\Checker.cs" />
<Compile Include="Pass.cs" />
<Compile Include="PassBuilder.cs" />
<Compile Include="Transforms\Transform.cs" />
<Compile Include="Utils\Glob.cs" />
<Compile Include="Generators\CLI\CLIHeadersTemplate.cs" />
<Compile Include="Generators\CLI\CLIMarshal.cs" />
<Compile Include="Generators\CLI\CLISourcesTemplate.cs" />
<Compile Include="Generators\Template.cs" />
<Compile Include="Utils\Options.cs" />
<Compile Include="CodeGenerator.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Libraries\SDL.cs" />
<Compile Include="Templates\CSharpModule.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>CSharpModule.tt</DependentUpon>
</Compile>
<Compile Include="Transform.cs" />
<Compile Include="Generators\CLI\CLIHelpers.cs" />
<Compile Include="Generators\CSharp\CSharpHelpers.cs" />
<Compile Include="LibraryHelpers.cs" />
<Compile Include="Types\Types.cs" />
<Compile Include="Transforms\Renames.cs" />
<Compile Include="Types\Std\Stdlib.cs" />
<Compile Include="Types\TypeMap.cs" />
<Compile Include="Utils\Utils.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="packages.config" />
<None Include="Templates\CSharpModule.tt">
<Generator>TextTemplatingFilePreprocessor</Generator>
<LastGenOutput>CSharpModule.cs</LastGenOutput>
</None>
<None Include="Generators\CSharp\CSharpModule.tt" />
</ItemGroup>
<ItemGroup>
<Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include=".NETFramework,Version=v4.0,Profile=Client">
<Visible>False</Visible>
<ProductName>Microsoft .NET Framework 4 Client Profile %28x86 and x64%29</ProductName>
<Install>true</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
<Install>false</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1</ProductName>
<Install>false</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Windows.Installer.4.5">
<Visible>False</Visible>
<ProductName>Windows Installer 4.5</ProductName>
<Install>true</Install>
</BootstrapperPackage>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Bridge\Bridge.csproj">
<Project>{6BEB8FA2-97AA-40B7-AB92-42F6EDDC4490}</Project>
<Project>{6beb8fa2-97aa-40b7-ab92-42f6eddc4490}</Project>
<Name>Bridge</Name>
</ProjectReference>
</ItemGroup>

22
src/Generator/Generator.csproj.user

@ -0,0 +1,22 @@ @@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<EnableUnmanagedDebugging>true</EnableUnmanagedDebugging>
<StartArguments>-ns=Flood -outdir=C:\Development\flood2\src\EngineManaged -IC:\development\flood2 -IC:\development\flood2\inc -assembly=Flood.dll Flood/Flood.cpp</StartArguments>
<StartWorkingDirectory>C:\Development\cxxi2\build\bin\</StartWorkingDirectory>
</PropertyGroup>
<PropertyGroup>
<ProjectView>ProjectFiles</ProjectView>
<PublishUrlHistory>publish\</PublishUrlHistory>
<InstallUrlHistory />
<SupportUrlHistory />
<UpdateUrlHistory />
<BootstrapperUrlHistory />
<ErrorReportUrlHistory />
<FallbackCulture>en-US</FallbackCulture>
<VerifyUploadedFiles>false</VerifyUploadedFiles>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<StartWorkingDirectory>C:\Development\cxxi2\build\bin\</StartWorkingDirectory>
</PropertyGroup>
</Project>

327
src/Generator/Generators/CLI/CLIHeadersTemplate.cs

@ -0,0 +1,327 @@ @@ -0,0 +1,327 @@
using System;
using System.Collections.Generic;
namespace Cxxi.Generators.CLI
{
public class CLIHeadersTemplate : CLITextTemplate
{
public override string FileExtension { get { return "h"; } }
protected override void Generate()
{
GenerateStart();
WriteLine("#pragma once");
NewLine();
WriteLine("#include <{0}>", Module.IncludePath);
NewLine();
WriteLine("namespace {0}", SafeIdentifier(Library.Name));
WriteLine("{");
GenerateDeclarations();
WriteLine("}");
}
public void GenerateForwardRefs()
{
// Use a set to remove duplicate entries.
var forwardRefs = new HashSet<string>();
foreach (var forwardRef in Module.ForwardReferences)
{
var printer = new CLIForwardRefeferencePrinter();
forwardRefs.Add(forwardRef.Visit(printer));
}
foreach (var forwardRef in forwardRefs)
{
WriteLine(forwardRef);
}
if (forwardRefs.Count > 0)
NewLine();
}
public void GenerateDeclarations()
{
PushIndent();
// Generate the forward references.
GenerateForwardRefs();
bool NeedsNewline = false;
// Generate all the enum declarations for the module.
for (int i = 0; i < Module.Enums.Count; ++i)
{
var E = Module.Enums[i];
if (E.Ignore) continue;
GenerateEnum(E);
NeedsNewline = true;
if (i < Module.Enums.Count - 1)
NewLine();
}
if (NeedsNewline)
NewLine();
NeedsNewline = false;
// Generate all the typedef declarations for the module.
for (var i = 0; i < Module.Typedefs.Count; ++i)
{
var T = Module.Typedefs[i];
if (T.Ignore) continue;
GenerateTypedef(T);
NeedsNewline = true;
if (i < Module.Typedefs.Count - 1)
NewLine();
}
if (NeedsNewline)
NewLine();
NeedsNewline = false;
// Generate all the struct/class declarations for the module.
for (var i = 0; i < Module.Classes.Count; ++i)
{
var @class = Module.Classes[i];
if (@class.Ignore || @class.IsIncomplete)
continue;
if (@class.IsOpaque)
continue;
GenerateClass(@class);
NeedsNewline = true;
if (i < Module.Classes.Count - 1)
NewLine();
}
if (Module.HasFunctions)
{
if (NeedsNewline)
NewLine();
WriteLine("public ref class {0}{1}", SafeIdentifier(Library.Name),
Module.FileNameWithoutExtension);
WriteLine("{");
WriteLine("public:");
PushIndent();
// Generate all the function declarations for the module.
foreach (var function in Module.Functions)
{
GenerateFunction(function);
}
PopIndent();
WriteLine("};");
}
PopIndent();
}
public void GenerateDeclarationCommon(Declaration T)
{
GenerateSummary(T.BriefComment);
GenerateDebug(T);
}
public void GenerateClass(Class @class)
{
if (@class.Ignore || @class.IsIncomplete)
return;
GenerateDeclarationCommon(@class);
if (@class.IsUnion)
WriteLine("[StructLayout(LayoutKind.Explicit)]");
Write("public ");
if (@class.IsValueType)
Write("value struct ");
else
Write("ref class ");
Write("{0}", SafeIdentifier(@class.Name));
if (@class.IsOpaque)
{
WriteLine(";");
return;
}
if (@class.HasBase)
Write(" : {0}", SafeIdentifier(@class.Bases[0].Class.Name));
WriteLine(string.Empty);
WriteLine("{");
WriteLine("public:");
if (!@class.IsValueType)
{
PushIndent();
var nativeType = string.Format("::{0}*", @class.OriginalName);
WriteLine("property {0} NativePtr;", nativeType);
PopIndent();
NewLine();
// Output a default constructor that takes the native pointer.
PushIndent();
WriteLine("{0}({1} native);", SafeIdentifier(@class.Name), nativeType);
PopIndent();
}
if (@class.IsValueType)
{
PushIndent();
foreach(var field in @class.Fields)
{
if (field.Ignore) continue;
GenerateDeclarationCommon(field);
if (@class.IsUnion)
WriteLine("[FieldOffset({0})]", field.Offset);
WriteLine("{0} {1};", field.Type, SafeIdentifier(field.Name));
}
PopIndent();
}
PushIndent();
foreach (var method in @class.Methods)
{
if (CheckIgnoreMethod(@class, method))
continue;
GenerateDeclarationCommon(method);
GenerateMethod(method);
}
PopIndent();
WriteLine("};");
}
public void GenerateMethod(Method method)
{
if (method.Ignore) return;
if (method.Access != AccessSpecifier.Public)
return;
GenerateDeclarationCommon(method);
if (method.Kind == CXXMethodKind.Constructor || method.Kind == CXXMethodKind.Destructor)
Write("{0}(", SafeIdentifier(method.Name));
else
Write("{0} {1}(", method.ReturnType, SafeIdentifier(method.Name));
for (int i = 0; i < method.Parameters.Count; ++i)
{
var param = method.Parameters[i];
Write("{0}", TypeSig.GetArgumentString(param));
if (i < method.Parameters.Count - 1)
Write(", ");
}
WriteLine(");");
}
public void GenerateTypedef(TypedefDecl typedef)
{
if (typedef.Ignore) return;
GenerateDeclarationCommon(typedef);
FunctionType func;
TagType tag;
//if (T.Type.IsPointerToPrimitiveType(PrimitiveType.Void)
// || T.Type.IsPointerTo<TagType>(out tag))
//{
// WriteLine("public class " + SafeIdentifier(T.Name) + @" { }");
// NewLine();
//}
//else
if (typedef.Type.IsPointerTo<FunctionType>(out func))
{
WriteLine("public {0};",
string.Format(TypeSig.ToDelegateString(func),
SafeIdentifier(typedef.Name)));
}
else if (typedef.Type.IsEnumType())
{
// Already handled in the parser.
}
else
{
Console.WriteLine("Unhandled typedef type: {0}", typedef);
}
}
public void GenerateFunction(Function function)
{
if (function.Ignore) return;
GenerateDeclarationCommon(function);
Write("static {0} {1}(", function.ReturnType, SafeIdentifier(function.Name));
for (int i = 0; i < function.Parameters.Count; ++i)
{
var param = function.Parameters[i];
Write("{0}", TypeSig.GetArgumentString(param));
if (i < function.Parameters.Count - 1)
Write(", ");
}
WriteLine(");");
}
public void GenerateDebug(Declaration decl)
{
if (Options.OutputDebug && !String.IsNullOrWhiteSpace(decl.DebugText))
WriteLine("// DEBUG: " + decl.DebugText);
}
public void GenerateEnum(Enumeration @enum)
{
if (@enum.Ignore) return;
GenerateDeclarationCommon(@enum);
if (@enum.Modifiers.HasFlag(Enumeration.EnumModifiers.Flags))
WriteLine("[System::Flags]");
Write("public enum struct {0}", SafeIdentifier(@enum.Name));
if (@enum.BuiltinType.Type != PrimitiveType.Int32)
WriteLine(" : {0}", TypeSig.VisitPrimitiveType(@enum.BuiltinType.Type));
else
NewLine();
WriteLine("{");
PushIndent();
for (int i = 0; i < @enum.Items.Count; ++i)
{
var I = @enum.Items[i];
GenerateInlineSummary(I.Comment);
if (I.ExplicitValue)
Write(String.Format("{0} = {1}", SafeIdentifier(I.Name), I.Value));
else
Write(String.Format("{0}", SafeIdentifier(I.Name)));
if (i < @enum.Items.Count - 1)
WriteLine(",");
}
PopIndent();
NewLine();
WriteLine("};");
}
}
}

449
src/Generator/Generators/CLI/CLIHelpers.cs

@ -0,0 +1,449 @@ @@ -0,0 +1,449 @@
using System;
using System.IO;
using Cxxi.Types;
namespace Cxxi.Generators.CLI
{
#region CLI Type Visitors
public class CLITypePrinter : ITypeVisitor<string>, IDeclVisitor<string>
{
public Generator Generator { get; set; }
public Library Library { get; set; }
public CLITypePrinter(Generator generator)
{
Generator = generator;
Library = generator.Library;
}
public string VisitTagType(TagType tag, TypeQualifiers quals)
{
Declaration decl = tag.Declaration;
if (decl == null)
return string.Empty;
return VisitDeclaration(decl, quals);
}
public string VisitArrayType(ArrayType array, TypeQualifiers quals)
{
return string.Format("array<{0}>", array.Type.Visit(this));
}
public string VisitFunctionType(FunctionType function, TypeQualifiers quals)
{
var arguments = function.Arguments;
var returnType = function.ReturnType;
string args = string.Empty;
if (arguments.Count > 0)
args = GetArgumentsString(function, hasNames: false);
if (returnType.IsPrimitiveType(PrimitiveType.Void))
{
if (!string.IsNullOrEmpty(args))
args = string.Format("<{0}>", args);
return string.Format("System::Action{0}", args);
}
if (!string.IsNullOrEmpty(args))
args = string.Format(", {0}", args);
return string.Format("System::Func<{0}{1}>", returnType.Visit(this), args);
}
public string GetArgumentsString(FunctionType function, bool hasNames)
{
var arguments = function.Arguments;
var s = string.Empty;
for (var i = 0; i < arguments.Count; ++i)
{
s += GetArgumentString(arguments[i], hasNames);
if (i < arguments.Count - 1)
s += ", ";
}
return s;
}
public string GetArgumentString(Parameter arg, bool hasName = true)
{
var quals = new TypeQualifiers {IsConst = arg.IsConst};
var type = arg.Type.Visit(this, quals);
var name = arg.Name;
if (hasName && !string.IsNullOrEmpty(name))
return string.Format("{0} {1}", type, name);
return type;
}
public string ToDelegateString(FunctionType function)
{
return string.Format("delegate {0} {{0}}({1})",
function.ReturnType.Visit(this),
GetArgumentsString(function, hasNames: true));
}
public string VisitPointerType(PointerType pointer, TypeQualifiers quals)
{
var pointee = pointer.Pointee;
if (pointee is FunctionType)
{
var function = pointee as FunctionType;
return string.Format("{0}^", function.Visit(this, quals));
}
if (pointee.IsPrimitiveType(PrimitiveType.Void))
return "System::IntPtr";
if (pointee.IsPrimitiveType(PrimitiveType.Char))
return "System::String^";
return pointee.Visit(this, quals);
}
public string VisitMemberPointerType(MemberPointerType member,
TypeQualifiers quals)
{
throw new NotImplementedException();
}
public string VisitBuiltinType(BuiltinType builtin, TypeQualifiers quals)
{
return VisitPrimitiveType(builtin.Type);
}
public string VisitPrimitiveType(PrimitiveType primitive)
{
switch (primitive)
{
case PrimitiveType.Bool: return "bool";
case PrimitiveType.Void: return "void";
case PrimitiveType.WideChar: return "char";
case PrimitiveType.Int8: return "char";
case PrimitiveType.UInt8: return "unsigned char";
case PrimitiveType.Int16: return "short";
case PrimitiveType.UInt16: return "unsigned short";
case PrimitiveType.Int32: return "int";
case PrimitiveType.UInt32: return "unsigned int";
case PrimitiveType.Int64: return "long";
case PrimitiveType.UInt64: return "unsigned long";
case PrimitiveType.Float: return "float";
case PrimitiveType.Double: return "double";
}
return string.Empty;
}
public string VisitTypedefType(TypedefType typedef, TypeQualifiers quals)
{
var decl = typedef.Declaration;
if (string.IsNullOrEmpty(decl.Name))
return null;
TypeMap typeMap = null;
if (Generator.TypeDatabase.FindTypeMap(decl.QualifiedOriginalName, out typeMap))
{
return typeMap.Signature();
}
FunctionType func;
if (typedef.Declaration.Type.IsPointerTo<FunctionType>(out func))
{
// TODO: Use SafeIdentifier()
return string.Format("{0}^", typedef.Declaration.Name);
}
return decl.Type.Visit(this);
}
public string VisitTemplateSpecializationType(TemplateSpecializationType template,
TypeQualifiers quals)
{
var decl = template.Template.TemplatedDecl;
TypeMap typeMap = null;
if (Generator.TypeDatabase.FindTypeMap(decl.QualifiedOriginalName, out typeMap))
{
typeMap.Declaration = decl;
typeMap.Type = template;
return typeMap.Signature();
}
return decl.Name;
}
public string VisitDeclaration(Declaration decl, TypeQualifiers quals)
{
return VisitDeclaration(decl);
}
public string VisitDeclaration(Declaration decl)
{
var name = decl.Visit(this);
return string.Format("{0}::{1}", Library.Name, name);
}
public string VisitClassDecl(Class @class)
{
return string.Format("{0}{1}", @class.Name, @class.IsRefType ? "^"
: string.Empty);
}
public string VisitFieldDecl(Field field)
{
throw new NotImplementedException();
}
public string VisitFunctionDecl(Function function)
{
throw new NotImplementedException();
}
public string VisitMethodDecl(Method method)
{
throw new NotImplementedException();
}
public string VisitParameterDecl(Parameter parameter)
{
throw new NotImplementedException();
}
public string VisitTypedefDecl(TypedefDecl typedef)
{
throw new NotImplementedException();
}
public string VisitEnumDecl(Enumeration @enum)
{
return @enum.Name;
}
public string VisitClassTemplateDecl(ClassTemplate template)
{
throw new NotImplementedException();
}
public string VisitFunctionTemplateDecl(FunctionTemplate template)
{
throw new NotImplementedException();
}
public string VisitMacroDefinition(MacroDefinition macro)
{
throw new NotImplementedException();
}
}
public class CLIForwardRefeferencePrinter : IDeclVisitor<string>
{
public string VisitDeclaration(Declaration decl)
{
throw new NotImplementedException();
}
public string VisitClassDecl(Class @class)
{
if (@class.IsValueType)
return string.Format("value struct {0};", @class.Name);
return string.Format("ref class {0};", @class.Name);
}
public string VisitFieldDecl(Field field)
{
throw new NotImplementedException();
}
public string VisitFunctionDecl(Function function)
{
throw new NotImplementedException();
}
public string VisitMethodDecl(Method method)
{
throw new NotImplementedException();
}
public string VisitParameterDecl(Parameter parameter)
{
throw new NotImplementedException();
}
public string VisitTypedefDecl(TypedefDecl typedef)
{
throw new NotImplementedException();
}
public string VisitEnumDecl(Enumeration @enum)
{
if (@enum.Type.IsPrimitiveType(PrimitiveType.Int32))
return string.Format("enum struct {0};", @enum.Name);
return string.Format("enum struct {0} : {1};", @enum.Name,
@enum.Type);
}
public string VisitClassTemplateDecl(ClassTemplate template)
{
throw new NotImplementedException();
}
public string VisitFunctionTemplateDecl(FunctionTemplate template)
{
throw new NotImplementedException();
}
public string VisitMacroDefinition(MacroDefinition macro)
{
throw new NotImplementedException();
}
}
#endregion
#region CLI Text Templates
public abstract class CLITextTemplate : TextTemplate
{
protected const string DefaultIndent = " ";
protected const uint MaxIndent = 80;
public CLITypePrinter TypeSig { get; set; }
public static string SafeIdentifier(string proposedName)
{
return proposedName;
}
public string QualifiedIdentifier(Declaration decl)
{
return string.Format("{0}::{1}", Library.Name, decl.Name);
}
public void GenerateStart()
{
Transform.GenerateStart(this);
}
public void GenerateAfterNamespaces()
{
Transform.GenerateAfterNamespaces(this);
}
public void GenerateSummary(string comment)
{
if (String.IsNullOrWhiteSpace(comment))
return;
// Wrap the comment to the line width.
var maxSize = (int)(MaxIndent - CurrentIndent.Count - "/// ".Length);
var lines = StringHelpers.WordWrapLines(comment, maxSize);
WriteLine("/// <summary>");
foreach (string line in lines)
WriteLine(string.Format("/// {0}", line.TrimEnd()));
WriteLine("/// </summary>");
}
public void GenerateInlineSummary(string comment)
{
if (String.IsNullOrWhiteSpace(comment))
return;
WriteLine("/// <summary> {0} </summary>", comment);
}
public static bool CheckIgnoreMethod(Class @class, Method method)
{
if (method.Ignore) return true;
if (@class.IsAbstract && method.IsConstructor)
return true;
if (@class.IsValueType && method.IsDefaultConstructor)
return true;
if (method.IsCopyConstructor || method.IsMoveConstructor)
return true;
if (method.IsDestructor)
return true;
if (method.OperatorKind == CXXOperatorKind.Equal)
return true;
if (method.Kind == CXXMethodKind.Conversion)
return true;
if (method.Access != AccessSpecifier.Public)
return true;
return false;
}
public abstract override string FileExtension { get; }
protected abstract override void Generate();
}
#endregion
public class CLIGenerator : ILanguageGenerator
{
public Options Options { get; set; }
public Library Library { get; set; }
public ILibrary Transform { get; set; }
public Generator Generator { get; set; }
private readonly CLITypePrinter typePrinter;
public CLIGenerator(Generator generator)
{
Generator = generator;
typePrinter = new CLITypePrinter(generator);
Type.TypePrinter = typePrinter;
}
T CreateTemplate<T>(TranslationUnit unit) where T : CLITextTemplate, new()
{
var template = new T
{
Generator = Generator,
Options = Options,
Library = Library,
Transform = Transform,
Module = unit,
TypeSig = typePrinter
};
return template;
}
void WriteTemplate(TextTemplate template)
{
var file = Path.GetFileNameWithoutExtension(template.Module.FileName) + "."
+ template.FileExtension;
var path = Path.Combine(Options.OutputDir, file);
Console.WriteLine(" Generated '" + file + "'.");
File.WriteAllText(Path.GetFullPath(path), template.ToString());
}
public bool Generate(TranslationUnit unit)
{
typePrinter.Library = Library;
var header = CreateTemplate<CLIHeadersTemplate>(unit);
WriteTemplate(header);
var source = CreateTemplate<CLISourcesTemplate>(unit);
WriteTemplate(source);
return true;
}
}
}

412
src/Generator/Generators/CLI/CLIMarshal.cs

@ -0,0 +1,412 @@ @@ -0,0 +1,412 @@
using System;
using System.Globalization;
using System.Text;
using Cxxi.Types;
namespace Cxxi.Generators.CLI
{
public class CLIMarshalNativeToManagedPrinter : ITypeVisitor<bool>,
IDeclVisitor<bool>
{
public string Support = null;
public string Return = null;
Generator Generator { get; set; }
MarshalContext Context { get; set; }
public CLIMarshalNativeToManagedPrinter(Generator gen, MarshalContext ctx)
{
Generator = gen;
Context = ctx;
}
public bool VisitTagType(TagType tag, TypeQualifiers quals)
{
var decl = tag.Declaration;
return decl.Visit(this);
}
public bool VisitArrayType(ArrayType array, TypeQualifiers quals)
{
return false;
}
public bool VisitFunctionType(FunctionType function, TypeQualifiers quals)
{
var returnType = function.ReturnType;
return returnType.Visit(this, quals);
}
public bool VisitPointerType(PointerType pointer, TypeQualifiers quals)
{
var pointee = pointer.Pointee;
if (pointee.IsPrimitiveType(PrimitiveType.Void))
{
Return = "IntPtr()";
return true;
}
if (pointee.IsPrimitiveType(PrimitiveType.Char))
{
Return = string.Format("clix::marshalString<clix::E_UTF8>({0})",
Context.ReturnVarName);
return true;
}
if (!pointee.Visit(this, quals))
return false;
if (pointer.IsReference)
Return = string.Format("&{0}", Return);
return true;
}
public bool VisitMemberPointerType(MemberPointerType member,
TypeQualifiers quals)
{
return false;
}
public bool VisitBuiltinType(BuiltinType builtin, TypeQualifiers quals)
{
return VisitPrimitiveType(builtin.Type);
}
public bool VisitPrimitiveType(PrimitiveType primitive)
{
switch (primitive)
{
case PrimitiveType.Void:
return true;
case PrimitiveType.Bool:
case PrimitiveType.Int8:
case PrimitiveType.UInt8:
case PrimitiveType.Int16:
case PrimitiveType.UInt16:
case PrimitiveType.Int32:
case PrimitiveType.UInt32:
case PrimitiveType.Int64:
case PrimitiveType.UInt64:
case PrimitiveType.Float:
case PrimitiveType.Double:
Return = Context.ReturnVarName;
return true;
case PrimitiveType.WideChar:
return false;
}
return false;
}
public bool VisitTypedefType(TypedefType typedef, TypeQualifiers quals)
{
var decl = typedef.Declaration;
TypeMap typeMap = null;
var typeDb = Generator.TypeDatabase;
if (typeDb.FindTypeMap(decl.QualifiedOriginalName, out typeMap))
{
Return = typeMap.MarshalFromNative(Context);
return typeMap.IsValueType;
}
// TODO: How should function pointers behave here?
return decl.Type.Visit(this);
}
public bool VisitTemplateSpecializationType(TemplateSpecializationType template,
TypeQualifiers quals)
{
return template.Template.Visit(this);
}
public bool VisitDeclaration(Declaration decl, TypeQualifiers quals)
{
throw new NotImplementedException();
}
public bool VisitDeclaration(Declaration decl)
{
throw new NotImplementedException();
}
public bool VisitClassDecl(Class @class)
{
Return = string.Format("gcnew {0}({1})", @class.Name, Context.ReturnVarName);
return @class.IsValueType;
}
public bool VisitFieldDecl(Field field)
{
throw new NotImplementedException();
}
public bool VisitFunctionDecl(Function function)
{
throw new NotImplementedException();
}
public bool VisitMethodDecl(Method method)
{
throw new NotImplementedException();
}
public bool VisitParameterDecl(Parameter parameter)
{
throw new NotImplementedException();
}
public bool VisitTypedefDecl(TypedefDecl typedef)
{
throw new NotImplementedException();
}
public bool VisitEnumDecl(Enumeration @enum)
{
Return = string.Format("({0}){1}", ToCLITypeName(@enum), Context.ReturnVarName);
return true;
}
private string ToCLITypeName(Declaration decl)
{
var typePrinter = new CLITypePrinter(Generator);
return typePrinter.VisitDeclaration(decl);
}
public bool VisitClassTemplateDecl(ClassTemplate template)
{
return template.TemplatedClass.Visit(this);
}
public bool VisitFunctionTemplateDecl(FunctionTemplate template)
{
throw new NotImplementedException();
}
public bool VisitMacroDefinition(MacroDefinition macro)
{
throw new NotImplementedException();
}
}
public class CLIMarshalManagedToNativePrinter : ITypeVisitor<bool>,
IDeclVisitor<bool>
{
public string Support = null;
public string Return = null;
Generator Generator { get; set; }
MarshalContext Context { get; set; }
public CLIMarshalManagedToNativePrinter(Generator gen, MarshalContext ctx)
{
Generator = gen;
Context = ctx;
}
public bool VisitTagType(TagType tag, TypeQualifiers quals)
{
var decl = tag.Declaration;
return decl.Visit(this);
}
public bool VisitArrayType(ArrayType array, TypeQualifiers quals)
{
return false;
}
public bool VisitFunctionType(FunctionType function, TypeQualifiers quals)
{
var returnType = function.ReturnType;
return returnType.Visit(this, quals);
}
public bool VisitDelegateType(FunctionType function, string type)
{
// We marshal function pointer types by calling
// GetFunctionPointerForDelegate to get a native function
// pointer ouf of the delegate. Then we can pass it in the
// native call. Since references are not tracked in the
// native side, we need to be careful and protect it with an
// explicit GCHandle if necessary.
var sb = new StringBuilder();
sb.AppendFormat("static_cast<::{0}>(", type);
sb.Append("System::Runtime::InteropServices::Marshal::");
sb.Append("GetFunctionPointerForDelegate(");
sb.AppendFormat("{0}).ToPointer())", Context.Parameter.Name);
Return = sb.ToString();
return true;
}
public bool VisitPointerType(PointerType pointer, TypeQualifiers quals)
{
var pointee = pointer.Pointee;
if (pointee.IsPrimitiveType(PrimitiveType.Void))
{
Return = string.Format("{0}.ToPointer()", Context.Parameter.Name);
return true;
}
if (pointee.IsPrimitiveType(PrimitiveType.Char))
{
Support = string.Format(
"auto _{0} = clix::marshalString<clix::E_UTF8>({1});",
Context.ArgName, Context.Parameter.Name);
Return = string.Format("_{0}.c_str()", Context.ArgName);
return true;
}
if (pointee is FunctionType)
{
var function = pointee as FunctionType;
// TODO: We have to translate the function type typedef to C/C++
return VisitDelegateType(function, function.ToString());
}
return pointee.Visit(this, quals);
}
public bool VisitMemberPointerType(MemberPointerType member,
TypeQualifiers quals)
{
return false;
}
public bool VisitBuiltinType(BuiltinType builtin, TypeQualifiers quals)
{
return VisitPrimitiveType(builtin.Type);
}
public bool VisitPrimitiveType(PrimitiveType primitive)
{
switch (primitive)
{
case PrimitiveType.Void:
return true;
case PrimitiveType.Bool:
case PrimitiveType.Int8:
case PrimitiveType.UInt8:
case PrimitiveType.Int16:
case PrimitiveType.UInt16:
case PrimitiveType.Int32:
case PrimitiveType.UInt32:
case PrimitiveType.Int64:
case PrimitiveType.UInt64:
case PrimitiveType.Float:
case PrimitiveType.Double:
Return = Context.Parameter.Name;
return true;
case PrimitiveType.WideChar:
return false;
}
return false;
}
public bool VisitTypedefType(TypedefType typedef, TypeQualifiers quals)
{
var decl = typedef.Declaration;
TypeMap typeMap = null;
if (Generator.TypeDatabase.FindTypeMap(decl.QualifiedOriginalName, out typeMap))
{
Return = typeMap.MarshalToNative(Context);
return typeMap.IsValueType;
}
FunctionType func;
if (typedef.Declaration.Type.IsPointerTo<FunctionType>(out func))
{
VisitDelegateType(func, typedef.Declaration.OriginalName);
return true;
}
return decl.Type.Visit(this);
}
public bool VisitTemplateSpecializationType(TemplateSpecializationType template,
TypeQualifiers quals)
{
return template.Template.Visit(this);
}
public bool VisitDeclaration(Declaration decl, TypeQualifiers quals)
{
throw new NotImplementedException();
}
public bool VisitDeclaration(Declaration decl)
{
throw new NotImplementedException();
}
public bool VisitClassDecl(Class @class)
{
if (@class.IsValueType)
{
Return = string.Format("(::{0}*)&{1}", @class.OriginalName,
Context.Parameter.Name);
}
else
{
Return = string.Format("{0}->NativePtr", Context.Parameter.Name);
}
return true;
}
public bool VisitFieldDecl(Field field)
{
throw new NotImplementedException();
}
public bool VisitFunctionDecl(Function function)
{
throw new NotImplementedException();
}
public bool VisitMethodDecl(Method method)
{
throw new NotImplementedException();
}
public bool VisitParameterDecl(Parameter parameter)
{
return parameter.Type.Visit(this);
}
public bool VisitTypedefDecl(TypedefDecl typedef)
{
throw new NotImplementedException();
}
public bool VisitEnumDecl(Enumeration @enum)
{
Return = string.Format("(::{0}){1}", @enum.QualifiedOriginalName,
Context.Parameter.Name);
return true;
}
public bool VisitClassTemplateDecl(ClassTemplate template)
{
return template.TemplatedClass.Visit(this);
}
public bool VisitFunctionTemplateDecl(FunctionTemplate template)
{
throw new NotImplementedException();
}
public bool VisitMacroDefinition(MacroDefinition macro)
{
throw new NotImplementedException();
}
}
}

285
src/Generator/Generators/CLI/CLISourcesTemplate.cs

@ -0,0 +1,285 @@ @@ -0,0 +1,285 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using Cxxi.Types;
namespace Cxxi.Generators.CLI
{
public class CLISourcesTemplate : CLITextTemplate
{
protected override void Generate()
{
GenerateStart();
WriteLine("#include \"{0}.h\"",
Path.GetFileNameWithoutExtension(Module.FileName));
NewLine();
GenerateForwardReferenceHeaders();
NewLine();
WriteLine("using namespace System;");
WriteLine("using namespace System::Runtime::InteropServices;");
GenerateAfterNamespaces();
NewLine();
GenerateDeclarations();
}
public void GenerateForwardReferenceHeaders()
{
var includes = new HashSet<string>();
// Generate the forward references.
foreach (var decl in Module.ForwardReferences)
{
var @namespace = decl.Namespace;
var unit = @namespace.TranslationUnit;
if (unit.Ignore)
continue;
if (unit.IsSystemHeader)
continue;
var includeName = Path.GetFileNameWithoutExtension(unit.FileName);
if (includeName == Path.GetFileNameWithoutExtension(Module.FileName))
continue;
includes.Add(includeName);
}
foreach (var include in includes)
{
WriteLine("#include \"{0}.h\"", include);
}
}
public void GenerateDeclarations()
{
// Generate all the struct/class definitions for the module.
for (var i = 0; i < Module.Classes.Count; ++i)
{
var @class = Module.Classes[i];
if (@class.Ignore)
continue;
if (@class.IsOpaque || @class.IsIncomplete)
continue;
GenerateClass(@class);
}
if (Module.HasFunctions)
{
var staticClassName = Library.Name + Module.FileNameWithoutExtension;
// Generate all the function declarations for the module.
for (var i = 0; i < Module.Functions.Count; ++i)
{
var function = Module.Functions[i];
if (function.Ignore)
continue;
GenerateFunction(function, staticClassName);
NewLine();
}
}
}
public void GenerateDeclarationCommon(Declaration decl)
{
}
public void GenerateClass(Class @class)
{
GenerateDeclarationCommon(@class);
if (!@class.IsValueType)
{
// Output a default constructor that takes the native pointer.
Write("{0}::{1}(", QualifiedIdentifier(@class), SafeIdentifier(@class.Name));
var nativeType = string.Format("::{0}*", @class.OriginalName);
WriteLine("{0} native)", nativeType);
WriteLine("{");
PushIndent();
WriteLine("NativePtr = native;");
PopIndent();
WriteLine("}");
NewLine();
}
foreach (var method in @class.Methods)
{
if (CheckIgnoreMethod(@class, method))
continue;
GenerateDeclarationCommon(method);
GenerateMethod(method, @class);
NewLine();
}
}
public void GenerateMethod(Method method, Class @class)
{
GenerateDeclarationCommon(method);
if (method.Kind == CXXMethodKind.Constructor || method.Kind == CXXMethodKind.Destructor)
Write("{0}::{1}(", QualifiedIdentifier(@class), SafeIdentifier(method.Name));
else
Write("{0} {1}::{2}(", method.ReturnType, QualifiedIdentifier(@class),
SafeIdentifier(method.Name));
for (var i = 0; i < method.Parameters.Count; ++i)
{
var param = method.Parameters[i];
Write("{0}", TypeSig.GetArgumentString(param));
if (i < method.Parameters.Count - 1)
Write(", ");
}
WriteLine(")");
WriteLine("{");
PushIndent();
if (@class.IsRefType)
{
if (method.Kind == CXXMethodKind.Constructor)
{
var @params = GenerateFunctionParamsMarshal(method);
Write("NativePtr = new ::{0}(", method.QualifiedOriginalName);
GenerateFunctionParams(method, @params);
WriteLine(");");
}
else
{
GenerateFunctionCall(method);
}
}
PopIndent();
WriteLine("}");
}
public void GenerateFunction(Function function, string className)
{
if (function.Ignore)
return;
GenerateDeclarationCommon(function);
Write("{0} {1}::{2}::{3}(", function.ReturnType, Library.Name, className,
SafeIdentifier(function.Name));
for (var i = 0; i < function.Parameters.Count; ++i)
{
var param = function.Parameters[i];
Write("{0}", TypeSig.GetArgumentString(param));
if (i < function.Parameters.Count - 1)
Write(", ");
}
WriteLine(")");
WriteLine("{");
PushIndent();
GenerateFunctionCall(function);
PopIndent();
WriteLine("}");
}
public void GenerateFunctionCall(Function function)
{
var retType = function.ReturnType;
var needsReturn = !retType.IsPrimitiveType(PrimitiveType.Void);
var @params = GenerateFunctionParamsMarshal(function);
if (needsReturn)
Write("auto ret = ");
if (function is Method)
Write("NativePtr->");
else
Write("::");
Write("{0}(", function.QualifiedOriginalName);
GenerateFunctionParams(function, @params);
WriteLine(");");
if (needsReturn)
{
Write("return ");
var ctx = new MarshalContext() { ReturnVarName = "ret" };
var marshal = new CLIMarshalNativeToManagedPrinter(Generator, ctx);
function.ReturnType.Visit(marshal);
WriteLine("{0};", marshal.Return);
}
}
public List<string> GenerateFunctionParamsMarshal(Function function)
{
var @params = new List<string>();
// Do marshalling of parameters
for (var i = 0; i < function.Parameters.Count; ++i)
{
var param = function.Parameters[i];
if (param.Type is BuiltinType)
{
@params.Add(param.Name);
}
else
{
var argName = "arg" + i.ToString(CultureInfo.InvariantCulture);
var ctx = new MarshalContext() { Parameter = param, ArgName = argName };
var marshal = new CLIMarshalManagedToNativePrinter(Generator, ctx);
param.Visit(marshal);
if (string.IsNullOrEmpty(marshal.Return))
return null;
if (!string.IsNullOrWhiteSpace(marshal.Support))
WriteLine(marshal.Support);
WriteLine("auto {0} = {1};", argName, marshal.Return);
@params.Add(argName);
}
}
return @params;
}
public void GenerateFunctionParams(Function function, List<string> @params)
{
for (var i = 0; i < @params.Count; ++i)
{
var param = @params[i];
Write(param);
if (i < @params.Count - 1)
Write(", ");
}
}
public void GenerateDebug(Declaration decl)
{
if (Options.OutputDebug && !String.IsNullOrWhiteSpace(decl.DebugText))
WriteLine("// DEBUG: " + decl.DebugText);
}
public override string FileExtension { get { return "cpp"; } }
}
}

142
src/Generator/Generators/CSharp/CSharpHelpers.cs

@ -0,0 +1,142 @@ @@ -0,0 +1,142 @@

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Cxxi.Generators;
namespace Cxxi.Templates.CSharp
{
class CSharpTypePrinter : ITypeVisitor<string>
{
public CSharpTypePrinter()
{
}
public string VisitTagType(TagType tag, TypeQualifiers quals)
{
throw new NotImplementedException();
}
public string VisitArrayType(ArrayType array, TypeQualifiers quals)
{
throw new NotImplementedException();
// C# only supports fixed arrays in unsafe sections
// and they are constrained to a set of built-in types.
//return string.Format("{0}[]", Type);
}
public string VisitFunctionType(FunctionType function, TypeQualifiers quals)
{
throw new NotImplementedException();
//string args = string.Empty;
//if (Arguments.Count > 0)
// args = ToArgumentString(hasNames: false);
//if (ReturnType.IsPrimitiveType(PrimitiveType.Void))
//{
// if (!string.IsNullOrEmpty(args))
// args = string.Format("<{0}>", args);
// return string.Format("Action{0}", args);
//}
//if (!string.IsNullOrEmpty(args))
// args = string.Format(", {0}", args);
//return string.Format("Func<{0}{1}>",
// ReturnType.ToCSharp(), args);
}
public string VisitPointerType(PointerType pointer, TypeQualifiers quals)
{
throw new NotImplementedException();
//if (Pointee is FunctionType)
//{
// var function = Pointee as FunctionType;
// return function.ToCSharp();
//}
//if (Pointee is TagType)
// return Pointee.ToCSharp();
//return "IntPtr";
//return string.Format("{0}{1}",
// Pointee.ToCSharp(), ConvertModifierToString(Modifier));
}
public string VisitMemberPointerType(MemberPointerType member,
TypeQualifiers quals)
{
throw new NotImplementedException();
}
public string VisitBuiltinType(BuiltinType builtin, TypeQualifiers quals)
{
throw new NotImplementedException();
}
public string VisitTypedefType(TypedefType typedef, TypeQualifiers quals)
{
throw new NotImplementedException();
}
public string VisitTemplateSpecializationType(TemplateSpecializationType template, TypeQualifiers quals)
{
throw new NotImplementedException();
}
public string VisitDeclaration(Declaration decl, TypeQualifiers quals)
{
throw new NotImplementedException();
}
public string GetArgumentString(Parameter arg, bool hasName)
{
throw new NotImplementedException();
//if (hasName && !string.IsNullOrEmpty(Name))
// return string.Format("{0} {1}", Type.ToCSharp(), Name);
//else
// return Type.ToCSharp();
}
}
public class CSharpModule : TextTemplate
{
// from https://github.com/mono/mono/blob/master/mcs/class/System/Microsoft.CSharp/CSharpCodeGenerator.cs
private static string[] keywords = new string[]
{
"abstract","event","new","struct","as","explicit","null","switch","base","extern",
"this","false","operator","throw","break","finally","out","true",
"fixed","override","try","case","params","typeof","catch","for",
"private","foreach","protected","checked","goto","public",
"unchecked","class","if","readonly","unsafe","const","implicit","ref",
"continue","in","return","using","virtual","default",
"interface","sealed","volatile","delegate","internal","do","is",
"sizeof","while","lock","stackalloc","else","static","enum",
"namespace",
"object","bool","byte","float","uint","char","ulong","ushort",
"decimal","int","sbyte","short","double","long","string","void",
"partial", "yield", "where"
};
public static string SafeIdentifier(string proposedName)
{
proposedName = new string(((IEnumerable<char>)proposedName).Select(c => char.IsLetterOrDigit(c) ? c : '_').ToArray());
return keywords.Contains(proposedName) ? "@" + proposedName : proposedName;
}
public override string FileExtension { get { return "cs"; } }
protected override void Generate()
{
throw new NotImplementedException();
}
}
}

261
src/Generator/Generators/CSharp/CSharpModule.tt

@ -0,0 +1,261 @@ @@ -0,0 +1,261 @@
<#@ template debug="true" language="C#" inherits="Cxxi.Templates.TextTemplate" #>
<#@ output extension=".cs" #>
using System;
using System.Runtime.InteropServices;
namespace <#= SafeIdentifier(Library.Name) #>
{
<#
GenerateDeclarations();
#>
}
<#+
public void GenerateDeclarations()
{
PushIndent(DefaultIndent);
bool NeedsNewline = false;
// Generate all the enum declarations for the module.
for(int i = 0; i < Module.Enums.Count; ++i)
{
var E = Module.Enums[i];
if (E.Ignore) continue;
GenerateEnum(E);
NeedsNewline = true;
if (i < Module.Enums.Count - 1)
WriteLine("");
}
if (NeedsNewline)
WriteLine("");
NeedsNewline = false;
// Generate all the typedef declarations for the module.
for(int i = 0; i < Module.Typedefs.Count; ++i)
{
var T = Module.Typedefs[i];
if (T.Ignore) continue;
GenerateTypedef(T);
NeedsNewline = true;
if (i < Module.Typedefs.Count - 1)
WriteLine("");
}
if (NeedsNewline)
WriteLine("");
NeedsNewline = false;
// Generate all the struct/class declarations for the module.
for(int i = 0; i < Module.Classes.Count; ++i)
{
var C = Module.Classes[i];
if (C.Ignore) continue;
GenerateClass(C);
NeedsNewline = true;
if (i < Module.Classes.Count - 1)
WriteLine("");
}
if (NeedsNewline)
WriteLine("");
if (Module.HasFunctions)
{
WriteLine("public partial class " + SafeIdentifier(Library.Name));
WriteLine("{");
PushIndent(DefaultIndent);
}
// Generate all the function declarations for the module.
foreach(var E in Module.Functions)
{
GenerateFunction(E);
}
if (Module.HasFunctions)
{
PopIndent();
WriteLine("}");
}
PopIndent();
}
#>
<#+
public void GenerateDeclarationCommon(Declaration T)
{
GenerateSummary(T.BriefComment);
GenerateDebug(T);
}
#>
<#+
public void GenerateClass(Class C)
{
if(C.Ignore) return;
GenerateDeclarationCommon(C);
if (C.IsUnion)
WriteLine("[StructLayout(LayoutKind.Explicit)]");
Write("public unsafe ");
if (C.IsAbstract)
Write("abstract ");
Write("class {0}", SafeIdentifier(C.Name));
if (C.HasBase)
Write(" : {0}", SafeIdentifier(C.Bases[0].Class.Name));
WriteLine(String.Empty);
WriteLine("{");
if (!C.IsOpaque)
{
PushIndent(DefaultIndent);
foreach(var F in C.Fields)
{
if (F.Ignore == true) continue;
GenerateDeclarationCommon(F);
if (C.IsUnion)
WriteLine("[FieldOffset({0})]", F.Offset);
WriteLine("public {0} {1};", F.Type, SafeIdentifier(F.Name));
}
PopIndent();
}
WriteLine("}");
}
#>
<#+
public void GenerateTypedef(TypedefDecl T)
{
if(T.Ignore) return;
GenerateDeclarationCommon(T);
FunctionType func;
TagType tag;
if (T.Type.IsPointerToPrimitiveType(PrimitiveType.Void)
|| T.Type.IsPointerTo<TagType>(out tag))
{
WriteLine("public class " + SafeIdentifier(T.Name) + @" { }");
WriteLine("");
}
else if(T.Type.IsPointerTo<FunctionType>(out func))
{
//WriteLine("public {0};",
// string.Format(func.ToDelegateString(), SafeIdentifier(T.Name)));
}
else if (T.Type.IsEnumType())
{
// Already handled in the parser.
}
else
{
Console.WriteLine("Unhandled typedef type: {0}", T);
}
}
#>
<#+
public void GenerateFunction(Function F)
{
if(F.Ignore) return;
GenerateDeclarationCommon(F);
#>
[DllImport("<#= SafeIdentifier(Library.Native) #>.dll",
CallingConvention = CallingConvention.<#= F.ToCSharpCallConv() #>,
EntryPoint="<#= F.Mangled #>")]
public unsafe static extern <#= F.ReturnType #> <#= SafeIdentifier(F.Name) #>(<#+
for(int i = 0; i < F.Parameters.Count; ++i)
{
var P = F.Parameters[i];
Write("{0} {1}", P.Type, SafeIdentifier(P.Name));
if (i < F.Parameters.Count - 1)
Write(", ");
}
#>);
<#+
WriteLine("");
}
#>
<#+
public void GenerateDebug(Declaration decl)
{
if(Options.OutputDebug && !String.IsNullOrWhiteSpace(decl.DebugText))
WriteLine("// DEBUG: " + decl.DebugText);
}
#>
<#+
public void GenerateSummary(string Comment)
{
if(String.IsNullOrWhiteSpace(Comment))
return;
#>
/// <summary>
/// <#= Comment #>
/// </summary>
<#+
}
#>
<#+
public void GenerateInlineSummary(string Comment)
{
if(String.IsNullOrWhiteSpace(Comment))
return;
#>
/// <summary> <#= Comment #> </summary>
<#+
}
#>
<#+
public void GenerateEnum(Enumeration E)
{
if(E.Ignore) return;
GenerateDeclarationCommon(E);
if(E.Modifiers.HasFlag(Enumeration.EnumModifiers.Flags))
WriteLine("[Flags]");
#>
public enum <#= SafeIdentifier(E.Name) #>
<#+
if(E.BuiltinType.Type != PrimitiveType.Int32)
WriteLine(" : {0}", E.BuiltinType.Type);
WriteLine("{");
PushIndent(DefaultIndent);
for(int i = 0; i < E.Items.Count; ++i)
{
var I = E.Items[i];
GenerateInlineSummary(I.Comment);
if (I.ExplicitValue)
Write(String.Format("{0} = {1}", SafeIdentifier(I.Name), I.Value));
else
Write(String.Format("{0}", SafeIdentifier(I.Name)));
if (i < E.Items.Count - 1)
WriteLine(",");
}
PopIndent();
WriteLine("");
#>
}
<#+
}
#>

94
src/Generator/Generators/Generator.cs

@ -0,0 +1,94 @@ @@ -0,0 +1,94 @@
using Cxxi.Generators.CLI;
using Cxxi.Types;
using System.IO;
namespace Cxxi.Generators
{
public enum LanguageGeneratorKind
{
CPlusPlusCLI,
CSharp
}
public interface ILanguageGenerator
{
Options Options { get; set; }
Library Library { get; set; }
ILibrary Transform { get; set; }
Generator Generator { get; set; }
bool Generate(TranslationUnit unit);
}
public partial class Generator
{
public Options Options;
public Library Library;
public ILibrary LibraryTransform;
public TypeDatabase TypeDatabase;
public Generator(Options options, Library library, ILibrary libraryTransform)
{
this.Options = options;
this.Library = library;
this.LibraryTransform = libraryTransform;
TypeDatabase = new TypeDatabase();
TypeDatabase.SetupTypeMaps();
}
public void Generate()
{
var generator = CreateLanguageGenerator(Options.Template);
if (!Directory.Exists(Options.OutputDir))
Directory.CreateDirectory(Options.OutputDir);
// Process everything in the global namespace for now.
foreach (var module in Library.TranslationUnits)
{
if (module.ExplicityIgnored || !module.HasDeclarations)
continue;
if (module.IsSystemHeader)
continue;
// Generate the target code.
generator.Generate(module);
}
}
ILanguageGenerator CreateLanguageGenerator(LanguageGeneratorKind kind)
{
ILanguageGenerator generator = null;
switch (kind)
{
case LanguageGeneratorKind.CPlusPlusCLI:
generator = new CLIGenerator(this);
break;
case LanguageGeneratorKind.CSharp:
//generator = new CSharpGenerator();
break;
}
generator.Options = Options;
generator.Library = Library;
generator.Transform = LibraryTransform;
return generator;
}
ILanguageGenerator CreateLanguageGenerator(string kind)
{
switch (kind)
{
default:
case "cli":
return CreateLanguageGenerator(LanguageGeneratorKind.CPlusPlusCLI);
case "cs":
return CreateLanguageGenerator(LanguageGeneratorKind.CSharp);
}
}
}
}

76
src/Generator/Generators/Template.cs

@ -0,0 +1,76 @@ @@ -0,0 +1,76 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Cxxi.Generators
{
public abstract class TextTemplate
{
private const uint DefaultIndent = 4;
private const uint MaxIndent = 80;
public Generator Generator { get; set; }
public Options Options { get; set; }
public Library Library { get; set; }
public ILibrary Transform;
public TranslationUnit Module { get; set; }
public abstract string FileExtension { get; }
protected abstract void Generate();
protected StringBuilder Builder;
protected Stack<uint> CurrentIndent;
private bool isStartOfLine;
protected TextTemplate()
{
Builder = new StringBuilder();
CurrentIndent = new Stack<uint>();
isStartOfLine = true;
}
public void Write(string msg, params object[] args)
{
if (isStartOfLine)
Builder.Append(new string(' ', (int)CurrentIndent.Sum(u => u)));
if (args.Length > 0)
msg = string.Format(msg, args);
if (msg.Length > 0)
isStartOfLine = false;
Builder.Append(msg);
}
public void WriteLine(string msg, params object[] args)
{
Write(msg, args);
NewLine();
}
public void NewLine()
{
Builder.AppendLine(string.Empty);
isStartOfLine = true;
}
public void PushIndent(uint indent = DefaultIndent)
{
CurrentIndent.Push(indent);
}
public void PopIndent()
{
CurrentIndent.Pop();
}
public override string ToString()
{
Builder.Clear();
Generate();
return Builder.ToString();
}
}
}

34
src/Generator/Glob.cs

@ -1,34 +0,0 @@ @@ -1,34 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
public static class Glob
{
static public string[] GetFiles(string[] patterns)
{
List<string> filelist = new List<string>();
foreach (string pattern in patterns)
filelist.AddRange(GetFiles(pattern));
string[] files = new string[filelist.Count];
filelist.CopyTo(files, 0);
return files;
}
static public string[] GetFiles(string patternlist)
{
List<string> filelist = new List<string>();
foreach (string pattern in
patternlist.Split(Path.GetInvalidPathChars()))
{
string dir = Path.GetDirectoryName(pattern);
if (String.IsNullOrEmpty(dir)) dir =
Directory.GetCurrentDirectory();
filelist.AddRange(Directory.GetFiles(
Path.GetFullPath(dir),
Path.GetFileName(pattern)));
}
string[] files = new string[filelist.Count];
filelist.CopyTo(files, 0);
return files;
}
}

79
src/Generator/Helpers.cs

@ -1,79 +0,0 @@ @@ -1,79 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Cxxi.Templates
{
public partial class CSharpModule
{
public Library Library;
public Options Options;
public Module Module;
readonly string DefaultIndent = " ";
// from https://github.com/mono/mono/blob/master/mcs/class/System/Microsoft.CSharp/CSharpCodeGenerator.cs
private static string[] keywords = new string[]
{
"abstract","event","new","struct","as","explicit","null","switch","base","extern",
"this","false","operator","throw","break","finally","out","true",
"fixed","override","try","case","params","typeof","catch","for",
"private","foreach","protected","checked","goto","public",
"unchecked","class","if","readonly","unsafe","const","implicit","ref",
"continue","in","return","using","virtual","default",
"interface","sealed","volatile","delegate","internal","do","is",
"sizeof","while","lock","stackalloc","else","static","enum",
"namespace",
"object","bool","byte","float","uint","char","ulong","ushort",
"decimal","int","sbyte","short","double","long","string","void",
"partial", "yield", "where"
};
public static string SafeIdentifier(string proposedName)
{
proposedName = new string(((IEnumerable<char>)proposedName).Select(c => char.IsLetterOrDigit(c) ? c : '_').ToArray());
return keywords.Contains(proposedName) ? "@" + proposedName : proposedName;
}
}
public static class IntHelpers
{
public static bool IsPowerOfTwo(this long x)
{
return (x != 0) && ((x & (x - 1)) == 0);
}
}
public static class StringHelpers
{
public static string CommonPrefix(this string[] ss)
{
if (ss.Length == 0)
{
return "";
}
if (ss.Length == 1)
{
return ss[0];
}
int prefixLength = 0;
foreach (char c in ss[0])
{
foreach (string s in ss)
{
if (s.Length <= prefixLength || s[prefixLength] != c)
{
return ss[0].Substring(0, prefixLength);
}
}
prefixLength++;
}
return ss[0]; // all strings identical
}
}
}

68
src/Generator/Libraries/Clang.cs

@ -1,68 +0,0 @@ @@ -1,68 +0,0 @@

namespace Cxxi
{
/// <summary>
/// Transform the Clang library declarations to something more .NET friendly.
/// </summary>
class ClangTransforms : LibraryTransform
{
public void Preprocess(Generator g)
{
//g.SetNameOfEnumWithMatchingItem("SDL_LOG_CATEGORY_CUSTOM", "LogCategory");
g.RemovePrefix("CX");
g.RemovePrefix("clang_");
g.RenameWithPattern("^_", string.Empty, RenameFlags.Declaration);
// Clean up types
g.FindClass("CXString").IsOpaque = true;
g.FindClass("CXSourceLocation").IsOpaque = true;
g.FindClass("CXSourceRange").IsOpaque = true;
g.FindClass("CXCursor").IsOpaque = true;
g.FindClass("CXType").IsOpaque = true;
g.FindClass("CXToken").IsOpaque = true;
g.FindClass("CXIdxLoc").IsOpaque = true;
g.FindClass("CXTranslationUnitImpl").IsOpaque = true;
// Clean up enums
g.RemovePrefixEnumItem("ChildVisit_");
g.RemovePrefixEnumItem("Comment_");
g.RemovePrefixEnumItem("Availability_");
g.RemovePrefixEnumItem("GlobalOpt_");
g.RemovePrefixEnumItem("Diagnostic_");
g.RemovePrefixEnumItem("LoadDiag_");
g.RemovePrefixEnumItem("TranslationUnit_");
g.RemovePrefixEnumItem("SaveTranslationUnit_");
g.RemovePrefixEnumItem("SaveError_");
g.RemovePrefixEnumItem("TranslationUnit_");
g.RemovePrefixEnumItem("Reparse_");
g.RemovePrefixEnumItem("TUResourceUsage_");
g.RemovePrefixEnumItem("Cursor_");
g.RemovePrefixEnumItem("Linkage_");
g.RemovePrefixEnumItem("Language_");
g.RemovePrefixEnumItem("Type_");
g.RemovePrefixEnumItem("CallingConv_");
g.RemovePrefixEnumItem("CommentInlineCommandRenderKind_");
g.RemovePrefixEnumItem("CommentParamPassDirection_");
g.RemovePrefixEnumItem("NameRange_");
g.RemovePrefixEnumItem("Token_");
g.RemovePrefixEnumItem("CompletionChunk_");
g.RemovePrefixEnumItem("CodeComplete_");
g.RemovePrefixEnumItem("CompletionContext_");
g.RemovePrefixEnumItem("Visit_");
g.RemovePrefixEnumItem("IdxEntity_");
g.RemovePrefixEnumItem("IdxEntityLang_");
g.RemovePrefixEnumItem("IdxAttr_");
g.RemovePrefixEnumItem("IdxObjCContainer_");
g.RemovePrefixEnumItem("IdxEntityRef_");
g.RemovePrefixEnumItem("IndexOpt_");
g.RemovePrefixEnumItem("IdxObjCContainer_");
}
public void Postprocess(Generator g)
{
g.FindEnum("CompletionContext").SetFlags();
g.FindClass("String").Name = "CXString";
//gen.SetNameOfEnumWithName("LOG_CATEGORY", "LogCategory");
}
}
}

60
src/Generator/Libraries/SDL.cs

@ -1,60 +0,0 @@ @@ -1,60 +0,0 @@

namespace Cxxi
{
/// <summary>
/// Transform the SDL library declarations to something more .NET friendly.
/// </summary>
class SDLTransforms : LibraryTransform
{
public void Preprocess(Generator g)
{
g.IgnoreEnumWithMatchingItem("SDL_FALSE");
g.IgnoreEnumWithMatchingItem("DUMMY_ENUM_VALUE");
g.SetNameOfEnumWithMatchingItem("SDL_SCANCODE_UNKNOWN", "ScanCode");
g.SetNameOfEnumWithMatchingItem("SDLK_UNKNOWN", "Key");
g.SetNameOfEnumWithMatchingItem("KMOD_NONE", "KeyModifier");
g.SetNameOfEnumWithMatchingItem("SDL_LOG_CATEGORY_CUSTOM", "LogCategory");
g.GenerateEnumFromMacros("InitFlags", "SDL_INIT_(.*)").SetFlags();
g.GenerateEnumFromMacros("Endianness", "SDL_(.*)_ENDIAN");
g.GenerateEnumFromMacros("InputState", "SDL_RELEASED", "SDL_PRESSED");
g.GenerateEnumFromMacros("AlphaState", "SDL_ALPHA_(.*)");
g.GenerateEnumFromMacros("HatState", "SDL_HAT_(.*)");
g.IgnoreModuleWithName("SDL_atomic*");
g.IgnoreModuleWithName("SDL_endian*");
g.IgnoreModuleWithName("SDL_main*");
g.IgnoreModuleWithName("SDL_mutex*");
g.IgnoreModuleWithName("SDL_stdinc*");
//g.IgnoreModuleWithName("SDL_error");
g.IgnoreEnumWithMatchingItem("SDL_ENOMEM");
g.IgnoreFunctionWithName("SDL_Error");
g.RemovePrefix("SDL_");
g.RemovePrefix("SCANCODE_");
g.RemovePrefix("SDLK_");
g.RemovePrefix("KMOD_");
g.RemovePrefix("LOG_CATEGORY_");
}
public void Postprocess(Generator g)
{
g.SetNameOfEnumWithName("PIXELTYPE", "PixelType");
g.SetNameOfEnumWithName("BITMAPORDER", "BitmapOrder");
g.SetNameOfEnumWithName("PACKEDORDER", "PackedOrder");
g.SetNameOfEnumWithName("ARRAYORDER", "ArrayOrder");
g.SetNameOfEnumWithName("PACKEDLAYOUT", "PackedLayout");
g.SetNameOfEnumWithName("PIXELFORMAT", "PixelFormats");
g.SetNameOfEnumWithName("assert_state", "AssertState");
g.SetNameOfClassWithName("assert_data", "AssertData");
g.SetNameOfEnumWithName("eventaction", "EventAction");
//gen.SetNameOfEnumWithName("LOG_CATEGORY", "LogCategory");
}
}
}

263
src/Generator/LibraryHelpers.cs

@ -0,0 +1,263 @@ @@ -0,0 +1,263 @@
using System;
using System.Globalization;
using System.Text.RegularExpressions;
using Cxxi.Generators;
namespace Cxxi
{
[AttributeUsage(AttributeTargets.Class)]
public class LibraryTransformAttribute : Attribute
{
}
/// <summary>
/// Used to massage the library types into something more .NET friendly.
/// </summary>
public interface ILibrary
{
/// <summary>
/// Do transformations that should happen before processing here.
/// </summary>
void Preprocess(LibraryHelpers g);
/// <summary>
/// Do transformations that should happen after processing here.
/// </summary>
void Postprocess(LibraryHelpers g);
/// <summary>
/// Setup your passes here.
/// </summary>
/// <param name="passes"></param>
void SetupPasses(PassBuilder passes);
/// <summary>
/// Called to generate text at the start of the text template.
/// </summary>
/// <param name="template"></param>
void GenerateStart(TextTemplate template);
/// <summary>
/// Called to generate text after the generation of namespaces.
/// </summary>
/// <param name="template"></param>
void GenerateAfterNamespaces(TextTemplate template);
}
public enum InlineMethods
{
Present,
Unavailable
}
public class LibraryHelpers
{
private Library Library { get; set; }
public LibraryHelpers(Library library)
{
Library = library;
}
#region Enum Helpers
public Enumeration FindEnum(string name)
{
foreach (var unit in Library.TranslationUnits)
{
var @enum = unit.FindEnum(name);
if (@enum != null)
return @enum;
}
return null;
}
public void IgnoreEnumWithMatchingItem(string pattern)
{
Enumeration @enum = GetEnumWithMatchingItem(pattern);
if (@enum != null)
@enum.ExplicityIgnored = true;
}
public void SetNameOfEnumWithMatchingItem(string pattern, string name)
{
Enumeration @enum = GetEnumWithMatchingItem(pattern);
if (@enum != null)
@enum.Name = name;
}
public void SetNameOfEnumWithName(string enumName, string name)
{
Enumeration @enum = FindEnum(enumName);
if (@enum != null)
@enum.Name = name;
}
public Enumeration GetEnumWithMatchingItem(string pattern)
{
foreach (var module in Library.TranslationUnits)
{
Enumeration @enum = module.FindEnumWithItem(pattern);
if (@enum == null) continue;
return @enum;
}
return null;
}
public Enumeration.Item GenerateEnumItemFromMacro(MacroDefinition macro)
{
var item = new Enumeration.Item
{
Name = macro.Name,
Expression = macro.Expression,
Value = ParseMacroExpression(macro.Expression)
};
return item;
}
static bool ParseToNumber(string num, out long val)
{
if (num.StartsWith("0x", StringComparison.CurrentCultureIgnoreCase))
{
num = num.Substring(2);
return long.TryParse(num, NumberStyles.HexNumber,
CultureInfo.CurrentCulture, out val);
}
return long.TryParse(num, out val);
}
static long ParseMacroExpression(string expression)
{
long val;
if (ParseToNumber(expression, out val))
return val;
// TODO: Handle string expressions
return 0;
}
public Enumeration GenerateEnumFromMacros(string name, params string[] macros)
{
var @enum = new Enumeration { Name = name };
var pattern = string.Join("|", macros);
var regex = new Regex(pattern);
foreach (var unit in Library.TranslationUnits)
{
foreach (var macro in unit.Macros)
{
var match = regex.Match(macro.Name);
if (!match.Success) continue;
var item = GenerateEnumItemFromMacro(macro);
@enum.AddItem(item);
}
if (@enum.Items.Count > 0)
{
unit.Enums.Add(@enum);
break;
}
}
return @enum;
}
#endregion
#region Class Helpers
public Class FindClass(string name)
{
foreach (var module in Library.TranslationUnits)
{
var @class = module.FindClass(name);
if (@class != null)
return @class;
}
return null;
}
public void SetClassBindName(string className, string name)
{
Class @class = FindClass(className);
if (@class != null)
@class.Name = name;
}
public void SetClassAsValueType(string className)
{
Class @class = FindClass(className);
if (@class != null)
@class.Type = ClassType.ValueType;
}
public void IgnoreClassWithName(string name)
{
Class @class = FindClass(name);
if (@class != null)
@class.ExplicityIgnored = true;
}
#endregion
#region Function Helpers
public Function FindFunction(string name)
{
foreach (var module in Library.TranslationUnits)
{
var function = module.FindFunction(name);
if (function != null)
return function;
}
return null;
}
public void IgnoreFunctionWithName(string name)
{
Function function = FindFunction(name);
if (function != null)
function.ExplicityIgnored = true;
}
public void IgnoreClassMethodWithName(string className, string name)
{
Class @class = FindClass(className);
if (@class == null)
return;
var method = @class.Methods.Find(m => m.Name == name);
if (method == null)
return;
method.ExplicityIgnored = true;
}
#endregion
#region Module Helpers
public void IgnoreModulessWithName(string pattern)
{
var modules = Library.TranslationUnits.FindAll(m =>
Regex.Match(m.FilePath, pattern).Success);
foreach (var module in modules)
{
module.ExplicityIgnored = true;
}
}
#endregion
}
}

76
src/Generator/Pass.cs

@ -0,0 +1,76 @@ @@ -0,0 +1,76 @@

namespace Cxxi.Passes
{
/// <summary>
/// Used to provide different types of code transformation on a module
/// declarations and types before the code generation process is started.
/// </summary>
public abstract class TranslationUnitPass
{
public Library Library { get; set; }
/// <summary>
/// Processes a library.
/// </summary>
public virtual bool ProcessLibrary(Library library)
{
return false;
}
/// <summary>
/// Processes a declaration.
/// </summary>
public virtual bool ProcessDeclaration(Declaration decl)
{
return false;
}
/// <summary>
/// Processes a class.
/// </summary>
public virtual bool ProcessClass(Class @class)
{
return false;
}
/// <summary>
/// Processes a field.
/// </summary>
public virtual bool ProcessField(Field field)
{
return false;
}
/// <summary>
/// Processes a function declaration.
/// </summary>
public virtual bool ProcessFunction(Function function)
{
return false;
}
/// <summary>
/// Processes a method declaration.
/// </summary>
public virtual bool ProcessMethod(Method method)
{
return false;
}
/// <summary>
/// Processes an enum declaration.
/// </summary>
public virtual bool ProcessEnum(Enumeration @enum)
{
return false;
}
/// <summary>
/// Processes an enum item.
/// </summary>
public virtual bool ProcessEnumItem(Enumeration.Item item)
{
return false;
}
}
}

50
src/Generator/PassBuilder.cs

@ -0,0 +1,50 @@ @@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Cxxi.Passes;
namespace Cxxi
{
/// <summary>
/// This class is used to build passes that will be run against the AST
/// that comes from C++.
/// </summary>
public class PassBuilder
{
public List<TranslationUnitPass> Passes { get; set; }
public PassBuilder()
{
Passes = new List<TranslationUnitPass>();
}
public void AddPass(TranslationUnitPass pass)
{
Passes.Add(pass);
}
#region Operation Helpers
public void RenameWithPattern(string pattern, string replacement, RenameTargets targets)
{
AddPass(new RegexRenamePass(pattern, replacement, targets));
}
public void RemovePrefix(string prefix)
{
AddPass(new RegexRenamePass("^" + prefix, String.Empty));
}
public void RemovePrefixEnumItem(string prefix)
{
AddPass(new RegexRenamePass("^" + prefix, String.Empty, RenameTargets.EnumItem));
}
public void RenameDeclsCase(RenameTargets targets, RenameCasePattern pattern)
{
AddPass(new CaseRenamePass(targets, pattern));
}
#endregion
}
}

158
src/Generator/Program.cs

@ -1,158 +0,0 @@ @@ -1,158 +0,0 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using Mono.Options;
using Cxxi;
public class Options
{
public Options()
{
IncludeDirs = new List<string>();
Headers = new List<string>();
}
public bool Verbose = false;
public bool ShowHelpText = false;
public bool OutputDebug = false;
public string OutputNamespace;
public string OutputDir;
public string Library;
public List<string> IncludeDirs;
public List<string> Headers;
}
class Program
{
Library library;
Options options;
static void ShowHelp(OptionSet options)
{
var module = Process.GetCurrentProcess().MainModule;
var exeName = Path.GetFileName(module.FileName);
Console.WriteLine("Usage: " + exeName + " [options]+ headers");
Console.WriteLine("Generates C# bindings from C/C++ header files.");
Console.WriteLine();
Console.WriteLine("Options:");
options.WriteOptionDescriptions(Console.Out);
}
bool ParseCommandLineOptions(String[] args)
{
var set = new OptionSet()
{
// Parser options
{ "C|compiler=", v => new object() },
{ "D|defines=", v => new object() },
{ "I|include=", v => options.IncludeDirs.Add(v) },
// Generator options
{ "ns|namespace=", v => options.OutputNamespace = v },
{ "o|outdir=", v => options.OutputDir = v },
{ "debug", v => options.OutputDebug = true },
{ "lib|library=", v => options.Library = v },
// Misc. options
{ "v|verbose", v => { options.Verbose = true; } },
{ "h|?|help", v => options.ShowHelpText = v != null },
};
if (args.Length == 0 || options.ShowHelpText)
{
ShowHelp(set);
return false;
}
try
{
options.Headers = set.Parse(args);
}
catch (OptionException)
{
Console.WriteLine("Error parsing the command line.");
ShowHelp(set);
return false;
}
return true;
}
public void GenerateCode(LibraryTransform transform)
{
Console.WriteLine("Generating wrapper code...");
if (library.Modules.Count > 0)
{
var gen = new Generator(library, options);
transform.Preprocess(gen);
gen.Process();
transform.Postprocess(gen);
gen.Generate();
}
}
public void ParseCode()
{
var Opts = new ParserOptions();
Opts.Library = library;
Opts.Verbose = false;
Opts.IncludeDirs = options.IncludeDirs;
Console.WriteLine("Parsing native code...");
foreach (var file in options.Headers)
{
var path = String.Empty;
try
{
path = Path.GetFullPath(file);
}
catch (ArgumentException)
{
Console.WriteLine("Invalid path '" + file + "'.");
continue;
}
var module = new Module(path);
Opts.FileName = path;
if (!ClangParser.Parse(Opts))
{
Console.WriteLine(" Could not parse '" + file + "'.");
continue;
}
Console.WriteLine(" Parsed '" + file + "'.");
}
}
public void Run(String[] args)
{
options = new Options();
if (!ParseCommandLineOptions(args))
return;
library = new Library(options.OutputNamespace, options.Library);
ParseCode();
//var transform = new SDLTransforms();
var transform = new ClangTransforms();
GenerateCode(transform);
}
static void Main(String[] args)
{
var program = new Program();
program.Run(args);
Console.ReadKey();
}
}

246
src/Generator/Templates/CSharpModule.tt

@ -1,246 +0,0 @@ @@ -1,246 +0,0 @@
<#@ template debug="true" language="C#" #>
<#@ output extension=".cs" #>
using System;
using System.Runtime.InteropServices;
namespace <#= SafeIdentifier(Library.Name) #>
{
<#
GenerateDeclarations();
#>
}
<#+
public void GenerateDeclarations()
{
PushIndent(DefaultIndent);
bool NeedsNewline = false;
// Generate all the enum declarations for the module.
for(int i = 0; i < Module.Enums.Count; ++i)
{
var E = Module.Enums[i];
if (E.Ignore) continue;
GenerateEnum(E);
NeedsNewline = true;
if (i < Module.Enums.Count - 1)
WriteLine("");
}
if (NeedsNewline)
WriteLine("");
NeedsNewline = false;
// Generate all the typedef declarations for the module.
for(int i = 0; i < Module.Typedefs.Count; ++i)
{
var T = Module.Typedefs[i];
if (T.Ignore) continue;
GenerateTypedef(T);
NeedsNewline = true;
if (i < Module.Typedefs.Count - 1)
WriteLine("");
}
if (NeedsNewline)
WriteLine("");
NeedsNewline = false;
// Generate all the struct/class declarations for the module.
for(int i = 0; i < Module.Classes.Count; ++i)
{
var C = Module.Classes[i];
if (C.Ignore) continue;
GenerateClass(C);
NeedsNewline = true;
if (i < Module.Classes.Count - 1)
WriteLine("");
}
if (NeedsNewline)
WriteLine("");
if (Module.HasFunctions)
{
WriteLine("public partial class " + SafeIdentifier(Library.Name));
WriteLine("{");
PushIndent(DefaultIndent);
}
// Generate all the function declarations for the module.
foreach(var E in Module.Functions)
{
GenerateFunction(E);
}
if (Module.HasFunctions)
{
PopIndent();
WriteLine("}");
}
PopIndent();
}
#>
<#+
public void GenerateDeclarationCommon(Declaration T)
{
GenerateSummary(T.BriefComment);
GenerateDebug(T);
}
#>
<#+
public void GenerateClass(Class C)
{
if(C.Ignore) return;
GenerateDeclarationCommon(C);
if (C.IsUnion)
WriteLine("[StructLayout(LayoutKind.Explicit)]");
Write("public unsafe ");
if (C.IsAbstract)
Write("abstract ");
Write("class {0}", SafeIdentifier(C.Name));
if (C.HasBase)
Write(" : {0}", SafeIdentifier(C.Bases[0].Class.Name));
WriteLine(String.Empty);
WriteLine("{");
if (!C.IsOpaque)
{
PushIndent(DefaultIndent);
foreach(var F in C.Fields)
{
GenerateDeclarationCommon(F);
if (C.IsUnion)
WriteLine("[FieldOffset({0})]", F.Offset);
WriteLine("public {0} {1};", F.Type.ToCSharp(), SafeIdentifier(F.Name));
}
PopIndent();
}
WriteLine("}");
}
#>
<#+
public void GenerateTypedef(Typedef T)
{
if(T.Ignore) return;
GenerateDeclarationCommon(T);
FunctionType func;
if (T.Type.IsPointerToPrimitiveType(PrimitiveType.Void))
{
WriteLine("public class " + SafeIdentifier(T.Name) + @" { }");
WriteLine("");
}
else if(T.Type.IsPointerTo<FunctionType>(out func))
{
WriteLine("public {0};",
string.Format(func.ToDelegateString(), SafeIdentifier(T.Name)));
}
}
#>
<#+
public void GenerateFunction(Function F)
{
if(F.Ignore) return;
GenerateDeclarationCommon(F);
#>
[DllImport("<#= SafeIdentifier(Library.Native) #>.dll")]
public unsafe static extern <#= F.ReturnType.ToCSharp() #> <#= SafeIdentifier(F.Name) #>(<#+
for(int i = 0; i < F.Parameters.Count; ++i)
{
var P = F.Parameters[i];
Write("{0} {1}", P.Type.ToCSharp(), SafeIdentifier(P.Name));
if (i < F.Parameters.Count - 1)
Write(", ");
}
#>);
<#+
WriteLine("");
}
#>
<#+
public void GenerateDebug(Declaration decl)
{
if(Options.OutputDebug && !String.IsNullOrWhiteSpace(decl.DebugText))
WriteLine("// DEBUG: " + decl.DebugText);
}
#>
<#+
public void GenerateSummary(string Comment)
{
if(String.IsNullOrWhiteSpace(Comment))
return;
#>
/// <summary>
/// <#= Comment #>
/// </summary>
<#+
}
#>
<#+
public void GenerateInlineSummary(string Comment)
{
if(String.IsNullOrWhiteSpace(Comment))
return;
#>
/// <summary> <#= Comment #> </summary>
<#+
}
#>
<#+
public void GenerateEnum(Enumeration E)
{
if(E.Ignore) return;
GenerateDeclarationCommon(E);
if(E.Modifiers.HasFlag(Enumeration.EnumModifiers.Flags))
WriteLine("[Flags]");
#>
public enum <#= SafeIdentifier(E.Name) #>
<#+
if(E.Type.Type != PrimitiveType.Int32)
WriteLine(" : {0}", E.Type.Type.ConvertToTypeName());
WriteLine("{");
PushIndent(DefaultIndent);
for(int i = 0; i < E.Items.Count; ++i)
{
var I = E.Items[i];
GenerateInlineSummary(I.Comment);
if (I.ExplicitValue)
Write(String.Format("{0} = {1}", SafeIdentifier(I.Name), I.Value));
else
Write(String.Format("{0}", SafeIdentifier(I.Name)));
if (i < E.Items.Count - 1)
WriteLine(",");
}
PopIndent();
WriteLine("");
#>
}
<#+
}
#>

313
src/Generator/Transform.cs

@ -1,313 +0,0 @@ @@ -1,313 +0,0 @@
using System;
using System.Diagnostics;
using System.Globalization;
using System.Text.RegularExpressions;
namespace Cxxi
{
/// <summary>
/// Used to massage the library types into something more .NET friendly.
/// </summary>
public interface LibraryTransform
{
/// <summary>
/// Do transformations that should happen before processing here.
/// </summary>
void Preprocess(Generator g);
/// <summary>
/// Do transformations that should happen after processing here.
/// </summary>
void Postprocess(Generator g);
}
/// <summary>
/// Used to provide different types of code transformation on a module
/// declarations and types before the code generation process is started.
/// </summary>
public abstract class ModuleTransform
{
/// <summary>
/// Processes a declaration.
/// </summary>
public virtual bool ProcessDeclaration(Declaration declaration)
{
return false;
}
/// <summary>
/// Processes an enum.
/// </summary>
public virtual bool ProcessEnum(Enumeration @enum)
{
return false;
}
/// <summary>
/// Processes an enum item.
/// </summary>
public virtual bool ProcessEnumItem(Enumeration.Item item)
{
return false;
}
}
[Flags]
public enum RenameFlags
{
Function,
Record,
Field,
Enum,
EnumItem,
Declaration = Function | Record | Field | Enum | EnumItem,
}
/// <summary>
/// Renames a declaration based on a regular expression pattern.
/// </summary>
public class RenameTransform : ModuleTransform
{
public string Pattern;
public string Replacement;
public RenameFlags Flags = RenameFlags.Declaration;
public RenameTransform(string pattern, string replacement)
{
Pattern = pattern;
Replacement = replacement;
}
public RenameTransform(string pattern, string replacement, RenameFlags flags)
: this(pattern, replacement)
{
Flags = flags;
}
public override bool ProcessDeclaration(Declaration type)
{
if (!Flags.HasFlag(RenameFlags.Declaration))
return false;
return Rename(ref type.Name);
}
public override bool ProcessEnumItem(Enumeration.Item item)
{
if (!Flags.HasFlag(RenameFlags.EnumItem))
return false;
return Rename(ref item.Name);
}
bool Rename(ref string name)
{
string replace = Regex.Replace(name, Pattern, Replacement);
if (!name.Equals(replace))
{
name = replace;
return true;
}
return false;
}
}
public partial class Generator
{
#region Transform Operations
public void RenameWithPattern(string pattern, string replacement, RenameFlags flags)
{
Transformations.Add(new RenameTransform(pattern, replacement, flags));
}
public void RemovePrefix(string prefix)
{
Transformations.Add(new RenameTransform("^"+prefix, String.Empty));
}
public void RemovePrefixEnumItem(string prefix)
{
Transformations.Add(new RenameTransform("^"+prefix, String.Empty, RenameFlags.EnumItem));
}
public void RemoveType(Declaration type)
{
throw new NotImplementedException();
}
#endregion
#region Enum Helpers
public Enumeration FindEnum(string name)
{
foreach (var module in Library.Modules)
{
var @enum = module.FindEnum(name);
if (@enum != null)
return @enum;
}
return null;
}
public void IgnoreEnumWithMatchingItem(string Pattern)
{
Enumeration @enum = GetEnumWithMatchingItem(Pattern);
if (@enum != null)
@enum.Ignore = true;
}
public void SetNameOfEnumWithMatchingItem(string Pattern, string Name)
{
Enumeration @enum = GetEnumWithMatchingItem(Pattern);
if (@enum != null)
@enum.Name = Name;
}
public void SetNameOfEnumWithName(string enumName, string name)
{
Enumeration @enum = FindEnum(enumName);
if (@enum != null)
@enum.Name = name;
}
public Enumeration GetEnumWithMatchingItem(string Pattern)
{
foreach (var module in Library.Modules)
{
Enumeration @enum = module.FindEnumWithItem(Pattern);
if (@enum == null) continue;
return @enum;
}
return null;
}
public Enumeration.Item GenerateEnumItemFromMacro(MacroDefine macro)
{
var item = new Enumeration.Item();
item.Name = macro.Name;
item.Expression = macro.Expression;
item.Value = ParseMacroExpression(macro.Expression);
return item;
}
public Enumeration GenerateEnumFromMacros(string name, params string[] macros)
{
Enumeration @enum = new Enumeration();
@enum.Name = name;
var pattern = String.Join("|", macros);
var regex = new Regex(pattern);
foreach (var module in Library.Modules)
{
foreach (var macro in module.Macros)
{
var match = regex.Match(macro.Name);
if (!match.Success) continue;
var item = GenerateEnumItemFromMacro(macro);
@enum.AddItem(item);
}
if (@enum.Items.Count > 0)
{
module.Enums.Add(@enum);
break;
}
}
return @enum;
}
#endregion
#region Class Helpers
public Class FindClass(string name)
{
foreach (var module in Library.Modules)
{
var @class = module.FindClass(name);
if (@class != null)
return @class;
}
return null;
}
public void SetNameOfClassWithName(string className, string name)
{
Class @class = FindClass(className);
if (@class != null)
@class.Name = name;
}
#endregion
#region Function Helpers
public Function FindFunction(string name)
{
foreach (var module in Library.Modules)
{
var function = module.FindFunction(name);
if (function != null)
return function;
}
return null;
}
public void IgnoreFunctionWithName(string name)
{
Function function = FindFunction(name);
if (function != null)
function.Ignore = true;
}
#endregion
#region Module Helpers
public Module IgnoreModuleWithName(string Pattern)
{
Module module = Library.Modules.Find(
m => Regex.Match(m.FilePath, Pattern).Success);
if (module != null)
module.Ignore = true;
return module;
}
#endregion
static bool ParseToNumber(string num, out long val)
{
if (num.StartsWith("0x", StringComparison.CurrentCultureIgnoreCase))
{
num = num.Substring(2);
return long.TryParse(num, NumberStyles.HexNumber,
CultureInfo.CurrentCulture, out val);
}
return long.TryParse(num, out val);
}
static long ParseMacroExpression(string Expression)
{
long val;
if (ParseToNumber(Expression, out val))
return val;
// TODO: Handle string expressions
return 0;
}
}
}

224
src/Generator/Transforms/Renames.cs

@ -0,0 +1,224 @@ @@ -0,0 +1,224 @@
using System;
using System.Text;
using System.Text.RegularExpressions;
namespace Cxxi.Passes
{
/// <summary>
/// Base class for transform that perform renames of declarations.
/// </summary>
public abstract class RenamePass : TranslationUnitPass
{
public RenameTargets Targets = RenameTargets.Any;
protected RenamePass()
{
}
protected RenamePass(RenameTargets targets)
{
Targets = targets;
}
}
[Flags]
public enum RenameTargets
{
Record,
Field,
Method,
Function,
Enum,
EnumItem,
Any = Function | Method | Record | Field | Enum | EnumItem,
}
/// <summary>
/// Renames a declaration based on a regular expression pattern.
/// </summary>
public class RegexRenamePass : RenamePass
{
public string Pattern;
public string Replacement;
public RegexRenamePass(string pattern, string replacement)
{
Pattern = pattern;
Replacement = replacement;
}
public RegexRenamePass(string pattern, string replacement,
RenameTargets targets)
: this(pattern, replacement)
{
Targets = targets;
}
public override bool ProcessDeclaration(Declaration decl)
{
if (!Targets.HasFlag(RenameTargets.Any))
return false;
string newName;
if (Rename(decl.Name, out newName))
{
decl.Name = newName;
return true;
}
return false;
}
public override bool ProcessEnumItem(Enumeration.Item item)
{
if (!Targets.HasFlag(RenameTargets.EnumItem))
return false;
string newName;
if (Rename(item.Name, out newName))
{
item.Name = newName;
return true;
}
return false;
}
public override bool ProcessField(Field field)
{
if (!Targets.HasFlag(RenameTargets.Field))
return false;
string newName;
if (Rename(field.Name, out newName))
{
field.Name = newName;
return true;
}
return false;
}
bool Rename(string name, out string newName)
{
var replace = Regex.Replace(name, Pattern, Replacement);
if (!name.Equals(replace))
{
newName = replace;
return true;
}
newName = null;
return false;
}
}
public enum RenameCasePattern
{
UpperCamelCase,
LowerCamelCase
}
/// <summary>
/// Renames a declaration based on a regular expression pattern.
/// </summary>
public class CaseRenamePass : RenamePass
{
public RenameCasePattern Pattern;
public CaseRenamePass(RenameTargets targets, RenameCasePattern pattern)
: base(targets)
{
Pattern = pattern;
}
private void Rename<T>(ref T decl) where T : Declaration
{
switch (Pattern)
{
case RenameCasePattern.LowerCamelCase:
decl.Name = ConvertCaseString(decl.Name, RenameCasePattern.LowerCamelCase);
break;
case RenameCasePattern.UpperCamelCase:
decl.Name = ConvertCaseString(decl.Name, RenameCasePattern.UpperCamelCase);
break;
}
}
public override bool ProcessDeclaration(Declaration decl)
{
if (!Targets.HasFlag(RenameTargets.Any))
return false;
Rename(ref decl);
return true;
}
public override bool ProcessFunction(Function function)
{
if (!Targets.HasFlag(RenameTargets.Function))
return false;
Rename(ref function);
return true;
}
public override bool ProcessField(Field field)
{
if (!Targets.HasFlag(RenameTargets.Field))
return false;
Rename(ref field);
return false;
}
public override bool ProcessMethod(Method method)
{
if (!Targets.HasFlag(RenameTargets.Method))
return false;
if (method.Kind != CXXMethodKind.Normal)
return false;
Rename(ref method);
return true;
}
/// <summary>
/// Converts the phrase to specified convention.
/// </summary>
/// <param name="phrase"></param>
/// <param name="pattern">The cases.</param>
/// <returns>string</returns>
static string ConvertCaseString(string phrase, RenameCasePattern pattern)
{
var splittedPhrase = phrase.Split(' ', '-', '.');
var sb = new StringBuilder();
switch (pattern)
{
case RenameCasePattern.LowerCamelCase:
sb.Append(splittedPhrase[0].ToLower());
splittedPhrase[0] = string.Empty;
break;
case RenameCasePattern.UpperCamelCase:
sb = new StringBuilder();
break;
}
foreach (var s in splittedPhrase)
{
var splittedPhraseChars = s.ToCharArray();
if (splittedPhraseChars.Length > 0)
{
var str = new String(splittedPhraseChars[0], 1);
splittedPhraseChars[0] = (str.ToUpper().ToCharArray())[0];
}
sb.Append(new String(splittedPhraseChars));
}
return sb.ToString();
}
}
}

164
src/Generator/Transforms/Transform.cs

@ -0,0 +1,164 @@ @@ -0,0 +1,164 @@
using System;
using System.Collections.Generic;
namespace Cxxi.Passes
{
public class Transform
{
public Options Options;
public PassBuilder Passes;
public void TransformLibrary(Library library)
{
if (string.IsNullOrEmpty(library.Name))
library.Name = string.Empty;
// Process everything in the global namespace for now.
foreach (var module in library.TranslationUnits)
TransformModule(module);
}
string GetIncludePath(string filePath)
{
string includePath = filePath;
foreach (var path in Options.IncludeDirs)
{
int idx = filePath.IndexOf(path, System.StringComparison.Ordinal);
if (idx == -1) continue;
string inc = filePath.Substring(path.Length);
if (inc.Length < includePath.Length)
includePath = inc;
}
return includePath.TrimStart(new char[] { '\\', '/' });
}
void TransformModule(TranslationUnit unit)
{
// Try to get an include path that works from the original include
// directories paths.
unit.IncludePath = GetIncludePath(unit.FilePath);
foreach (var @enum in unit.Enums)
TransformEnum(@enum);
foreach (var function in unit.Functions)
TransformFunction(function);
foreach (var @class in unit.Classes)
TransformClass(@class);
foreach (var typedef in unit.Typedefs)
TransformTypedef(typedef);
}
void TransformDeclaration(Declaration decl)
{
foreach (var pass in Passes.Passes)
pass.ProcessDeclaration(decl);
}
void TransformTypedef(TypedefDecl typedef)
{
foreach (var pass in Passes.Passes)
pass.ProcessDeclaration(typedef);
}
void TransformClass(Class @class)
{
TransformDeclaration(@class);
foreach (var method in @class.Methods)
{
foreach (var pass in Passes.Passes)
pass.ProcessMethod(method);
}
foreach (var field in @class.Fields)
{
foreach (var pass in Passes.Passes)
pass.ProcessField(field);
TransformDeclaration(field);
}
}
void TransformFunction(Function function)
{
foreach (var pass in Passes.Passes)
pass.ProcessFunction(function);
TransformDeclaration(function);
foreach (var param in function.Parameters)
TransformDeclaration(param);
}
void TransformEnum(Enumeration @enum)
{
TransformDeclaration(@enum);
foreach (var item in @enum.Items)
{
foreach (var pass in Passes.Passes)
pass.ProcessEnumItem(item);
}
CheckIsFlagsEnum(@enum);
// If we still do not have a valid name, then try to guess one
// based on the enum value names.
if (!String.IsNullOrWhiteSpace(@enum.Name))
return;
var names = new List<string>();
foreach (var item in @enum.Items)
names.Add(item.Name);
var prefix = names.ToArray().CommonPrefix();
// Try a simple heuristic to make sure we end up with a valid name.
if (prefix.Length >= 3)
{
prefix = prefix.Trim().Trim(new char[] { '_' });
@enum.Name = prefix;
}
}
private static void CheckIsFlagsEnum(Enumeration @enum)
{
// If the enumeration only has power of two values, assume it's
// a flags enum.
bool isFlags = true;
bool hasBigRange = false;
foreach (var item in @enum.Items)
{
if (item.Name.Length >= 1 && Char.IsDigit(item.Name[0]))
item.Name = String.Format("_{0}", item.Name);
long value = item.Value;
if (value >= 4)
hasBigRange = true;
if (value <= 1 || value.IsPowerOfTwo())
continue;
isFlags = false;
}
// Only apply this heuristic if there are enough values to have a
// reasonable chance that it really is a bitfield.
if (isFlags && hasBigRange)
{
@enum.Modifiers |= Enumeration.EnumModifiers.Flags;
}
}
}
}

187
src/Generator/Types/Checker.cs

@ -0,0 +1,187 @@ @@ -0,0 +1,187 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Cxxi.Passes
{
public class Preprocess : TranslationUnitPass
{
private int uniqueName;
private TypeRefsVisitor typeRefs;
public Preprocess()
{
typeRefs = new TypeRefsVisitor();
}
public void ProcessLibrary(Library Library)
{
if (string.IsNullOrEmpty(Library.Name))
Library.Name = "";
// Process everything in the global namespace for now.
foreach (var unit in Library.TranslationUnits)
{
if (unit.ExplicityIgnored)
continue;
if (unit.IsSystemHeader)
continue;
typeRefs = new TypeRefsVisitor();
ProcessNamespace(unit);
unit.ForwardReferences = typeRefs.ForwardReferences.ToList();
}
}
private void ProcessNamespace(Namespace @namespace)
{
ProcessDeclarations(@namespace.Enums);
ProcessFunctions(@namespace.Functions);
ProcessClasses(@namespace.Classes);
ProcessTypedefs(@namespace, @namespace.Typedefs);
foreach (var inner in @namespace.Namespaces)
ProcessNamespace(inner);
}
public override bool ProcessDeclaration(Declaration decl)
{
decl.Visit(typeRefs);
// Generate a new name if the decl still does not have a name
if (string.IsNullOrWhiteSpace(decl.Name))
decl.Name = string.Format("_{0}", uniqueName++);
StringHelpers.CleanupText(ref decl.DebugText);
return true;
}
private void ProcessDeclarations<T>(IEnumerable<T> decls) where T : Declaration
{
foreach (T decl in decls)
ProcessDeclaration(decl);
}
private void ProcessClasses(List<Class> classes)
{
ProcessDeclarations(classes);
foreach (var @class in classes)
{
ProcessFields(@class.Fields);
ProcessMethods(@class.Methods);
}
}
private void ProcessFields(List<Field> fields)
{
ProcessDeclarations(fields);
foreach (var field in fields)
{
var type = field.Type;
if (type == null || !IsTypeComplete(type) || IsTypeIgnored(type))
{
field.ExplicityIgnored = true;
Console.WriteLine(
"Field '{0}' was ignored due to unknown / ignored type",
field.Name);
}
}
}
public override bool ProcessFunction(Function function)
{
var ret = function.ReturnType;
if (ret == null || !IsTypeComplete(ret) || IsTypeIgnored(ret))
{
function.ExplicityIgnored = true;
Console.WriteLine(
"Function '{0}' was ignored due to unknown / ignored return decl",
function.Name);
}
foreach (var param in function.Parameters)
{
if (param == null || !IsDeclComplete(param) || IsDeclIgnored(param))
{
function.ExplicityIgnored = true;
Console.WriteLine(
"Function '{0}' was ignored due to unknown / ignored param",
function.Name);
}
ProcessDeclaration(param);
}
return true;
}
private static bool IsTypeComplete(Type type)
{
var checker = new TypeCompletionChecker();
return type.Visit(checker);
}
private static bool IsDeclComplete(Declaration decl)
{
var checker = new TypeCompletionChecker();
return decl.Visit(checker);
}
private static bool IsTypeIgnored(Type type)
{
var checker = new TypeIgnoreChecker();
return type.Visit(checker);
}
private static bool IsDeclIgnored(Declaration decl)
{
var checker = new TypeIgnoreChecker();
return decl.Visit(checker);
}
public override bool ProcessMethod(Method method)
{
return ProcessFunction(method);
}
private void ProcessMethods(List<Method> methods)
{
ProcessDeclarations(methods);
foreach (var method in methods)
ProcessFunction(method);
}
private void ProcessTypedefs(Namespace @namespace, List<TypedefDecl> typedefs)
{
ProcessDeclarations(typedefs);
foreach (var typedef in typedefs)
{
var @class = @namespace.FindClass(typedef.Name);
// Clang will walk the typedef'd tag decl and the typedef decl,
// so we ignore the class and process just the typedef.
if (@class != null)
typedef.ExplicityIgnored = true;
if (typedef.Type == null)
typedef.ExplicityIgnored = true;
}
}
private void ProcessFunctions(List<Function> functions)
{
ProcessDeclarations(functions);
foreach (var function in functions)
ProcessFunction(function);
}
}
}

84
src/Generator/Types/Std/Stdlib.cs

@ -0,0 +1,84 @@ @@ -0,0 +1,84 @@
namespace Cxxi.Types.Std
{
[TypeMap("std::string")]
[TypeMap("std::wstring")]
public class String : TypeMap
{
public override string Signature()
{
return "System::String^";
}
public override string MarshalToNative(MarshalContext ctx)
{
return string.Format("marshalString<E_UTF8>({0})", ctx.Parameter.Name);
}
public override string MarshalFromNative(MarshalContext ctx)
{
return string.Format("marshalString<E_UTF8>({0})", ctx.ReturnVarName);
}
}
[TypeMap("std::vector")]
public class Vector : TypeMap
{
public override string Signature()
{
var type = Type as TemplateSpecializationType;
var typeName = type.Arguments[0].Type.ToString();
return string.Format("System::Collections::Generic::List<{0}>^", typeName);
}
public override string MarshalToNative(MarshalContext ctx)
{
throw new System.NotImplementedException();
}
public override string MarshalFromNative(MarshalContext ctx)
{
throw new System.NotImplementedException();
}
}
[TypeMap("std::map")]
public class Map : TypeMap
{
public override string Signature()
{
var type = Type as TemplateSpecializationType;
return string.Format("System::Collections::Generic::Dictionary<{0}, {1}>^",
type.Arguments[0].Type,
type.Arguments[1].Type);
}
public override string MarshalToNative(MarshalContext ctx)
{
throw new System.NotImplementedException();
}
public override string MarshalFromNative(MarshalContext ctx)
{
throw new System.NotImplementedException();
}
}
[TypeMap("std::shared_ptr")]
public class SharedPtr : TypeMap
{
public override string Signature()
{
throw new System.NotImplementedException();
}
public override string MarshalToNative(MarshalContext ctx)
{
throw new System.NotImplementedException();
}
public override string MarshalFromNative(MarshalContext ctx)
{
throw new System.NotImplementedException();
}
}
}

92
src/Generator/Types/TypeMap.cs

@ -0,0 +1,92 @@ @@ -0,0 +1,92 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace Cxxi.Types
{
public class MarshalContext
{
public string ArgName { get; set; }
public string ReturnVarName { get; set; }
public Parameter Parameter { get; set; }
}
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public class TypeMapAttribute : Attribute
{
public string Type { get; private set; }
public TypeMapAttribute(string type)
{
Type = type;
}
}
/// <summary>
/// This is similar to the SWIG type map concept, and allows some
/// freedom and customization when translating between the source and
/// target language types.
/// </summary>
public abstract class TypeMap
{
public Type Type { get; set; }
public Declaration Declaration { get; set; }
public virtual bool IsValueType
{
get { return false; }
}
public abstract string Signature();
public abstract string MarshalToNative(MarshalContext ctx);
public abstract string MarshalFromNative(MarshalContext ctx);
}
public class TypeDatabase
{
public IDictionary<string, System.Type> TypeMaps { get; set; }
public TypeDatabase()
{
TypeMaps = new Dictionary<string, System.Type>();
}
public void SetupTypeMaps()
{
var loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (var assembly in loadedAssemblies)
{
var types = assembly.FindDerivedTypes(typeof(TypeMap));
foreach (var typeMap in types)
{
var attrs = typeMap.GetCustomAttributes<TypeMapAttribute>();
if (attrs == null) continue;
foreach (var attr in attrs)
{
Console.WriteLine("Found typemap: {0}", attr.Type);
TypeMaps[attr.Type] = typeMap;
}
}
}
}
public bool FindTypeMap(string name, out TypeMap typeMap)
{
System.Type type;
TypeMaps.TryGetValue(name, out type);
if (type == null)
{
typeMap = null;
return false;
}
typeMap = (TypeMap)Activator.CreateInstance(type);
return true;
}
}
}

276
src/Generator/Types/Types.cs

@ -0,0 +1,276 @@ @@ -0,0 +1,276 @@
using System.Collections.Generic;
namespace Cxxi
{
/// <summary>
/// Base class for type checkers.
/// You can override the methods to customize the behaviour, by default
/// this will visit all the nodes in a default way that should be useful
/// for a lot of applications.
/// </summary>
public abstract class TypeChecker : ITypeVisitor<bool>, IDeclVisitor<bool>
{
public virtual bool VisitTagType(TagType tag, TypeQualifiers quals)
{
return tag.Declaration.Visit(this);
}
public virtual bool VisitArrayType(ArrayType array, TypeQualifiers quals)
{
return array.Type.Visit(this, quals);
}
public virtual bool VisitFunctionType(FunctionType function, TypeQualifiers quals)
{
if (function.ReturnType != null)
function.ReturnType.Visit(this);
foreach (var param in function.Arguments)
param.Visit(this);
return true;
}
public virtual bool VisitPointerType(PointerType pointer, TypeQualifiers quals)
{
if (pointer.Pointee == null)
return false;
return pointer.Pointee.Visit(this, quals);
}
public virtual bool VisitMemberPointerType(MemberPointerType member, TypeQualifiers quals)
{
return member.Pointee.Visit(this, quals);
}
public virtual bool VisitBuiltinType(BuiltinType builtin, TypeQualifiers quals)
{
return true;
}
public virtual bool VisitTypedefType(TypedefType typedef, TypeQualifiers quals)
{
return typedef.Declaration.Visit(this);
}
public virtual bool VisitTemplateSpecializationType(TemplateSpecializationType template, TypeQualifiers quals)
{
return template.Template.Visit(this);
}
public virtual bool VisitDeclaration(Declaration decl, TypeQualifiers quals)
{
return VisitDeclaration(decl);
}
public virtual bool VisitDeclaration(Declaration decl)
{
return true;
}
public virtual bool VisitClassDecl(Class @class)
{
return VisitDeclaration(@class);
}
public virtual bool VisitFieldDecl(Field field)
{
return field.Type.Visit(this);
}
public virtual bool VisitFunctionDecl(Function function)
{
if (function.ReturnType == null)
return false;
function.ReturnType.Visit(this);
foreach (var param in function.Parameters)
param.Visit(this);
return true;
}
public virtual bool VisitMethodDecl(Method method)
{
return VisitFunctionDecl(method);
}
public virtual bool VisitParameterDecl(Parameter parameter)
{
return parameter.Type.Visit(this);
}
public virtual bool VisitTypedefDecl(TypedefDecl typedef)
{
if (typedef.Type == null)
return false;
return typedef.Type.Visit(this);
}
public virtual bool VisitEnumDecl(Enumeration @enum)
{
return VisitDeclaration(@enum);
}
public virtual bool VisitClassTemplateDecl(ClassTemplate template)
{
return template.TemplatedClass.Visit(this);
}
public virtual bool VisitFunctionTemplateDecl(FunctionTemplate template)
{
return template.TemplatedFunction.Visit(this);
}
public virtual bool VisitMacroDefinition(MacroDefinition macro)
{
return true;
}
}
/// <summary>
/// This type checker is used to check if a type is complete.
/// </summary>
public class TypeCompletionChecker : TypeChecker
{
public override bool VisitDeclaration(Declaration decl)
{
return !decl.IsIncomplete;
}
public override bool VisitBuiltinType(BuiltinType builtin, TypeQualifiers quals)
{
return true;
}
public override bool VisitFunctionType(FunctionType function, TypeQualifiers quals)
{
if (!function.ReturnType.Visit(this))
return false;
foreach (var arg in function.Arguments)
{
if (!arg.Type.Visit(this))
return false;
}
return true;
}
public override bool VisitFunctionDecl(Function function)
{
if (!function.ReturnType.Visit(this))
return false;
foreach (var param in function.Parameters)
{
if (!param.Visit(this))
return false;
}
return true;
}
}
/// <summary>
/// This type checker is used to check if a type is ignored.
/// </summary>
public class TypeIgnoreChecker : TypeChecker
{
public override bool VisitDeclaration(Declaration decl)
{
return decl.Ignore;
}
public override bool VisitBuiltinType(BuiltinType builtin, TypeQualifiers quals)
{
return false;
}
public override bool VisitFunctionType(FunctionType function, TypeQualifiers quals)
{
if (!function.ReturnType.Visit(this))
return false;
foreach (var arg in function.Arguments)
{
if (!arg.Type.Visit(this))
return false;
}
return true;
}
public override bool VisitFunctionDecl(Function function)
{
if (!function.ReturnType.Visit(this))
return false;
foreach (var param in function.Parameters)
{
if (!param.Visit(this))
return false;
}
return true;
}
}
/// <summary>
/// This is used to get the declarations that each file needs to forward
/// reference or include from other header files. Since in C++ everything
/// that is referenced needs to have been declared previously, it can happen
/// that a file needs to be reference something that has not been declared
/// yet. In that case, we need to declare it before referencing it.
/// </summary>
class TypeRefsVisitor : TypeChecker
{
public ISet<Declaration> ForwardReferences;
public void Collect(Declaration declaration)
{
if (declaration.Namespace.TranslationUnit.IsSystemHeader)
return;
ForwardReferences.Add(declaration);
}
public TypeRefsVisitor()
{
ForwardReferences = new HashSet<Declaration>();
}
public override bool VisitBuiltinType(BuiltinType builtin, TypeQualifiers quals)
{
// Built-in types should not need forward references.
return true;
}
public override bool VisitClassDecl(Class @class)
{
Collect(@class);
return true;
}
public override bool VisitParameterDecl(Parameter parameter)
{
if (parameter.Type == null)
return false;
return parameter.Type.Visit(this);
}
public override bool VisitEnumDecl(Enumeration @enum)
{
Collect(@enum);
return @enum.Type.Visit(this, new TypeQualifiers());
}
public override bool VisitMacroDefinition(MacroDefinition macro)
{
// Macros are not relevant for forward references.
return true;
}
}
}

34
src/Generator/Utils/Glob.cs

@ -0,0 +1,34 @@ @@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.IO;
public static class Glob
{
static public string[] GetFiles(string[] patterns)
{
List<string> filelist = new List<string>();
foreach (string pattern in patterns)
filelist.AddRange(GetFiles(pattern));
string[] files = new string[filelist.Count];
filelist.CopyTo(files, 0);
return files;
}
static public string[] GetFiles(string patternlist)
{
List<string> filelist = new List<string>();
foreach (string pattern in
patternlist.Split(Path.GetInvalidPathChars()))
{
string dir = Path.GetDirectoryName(pattern);
if (String.IsNullOrEmpty(dir)) dir =
Directory.GetCurrentDirectory();
filelist.AddRange(Directory.GetFiles(
Path.GetFullPath(dir),
Path.GetFileName(pattern)));
}
string[] files = new string[filelist.Count];
filelist.CopyTo(files, 0);
return files;
}
}

0
src/Generator/Options.cs → src/Generator/Utils/Options.cs

176
src/Generator/Utils/Utils.cs

@ -0,0 +1,176 @@ @@ -0,0 +1,176 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
namespace Cxxi
{
public static class IntHelpers
{
public static bool IsPowerOfTwo(this long x)
{
return (x != 0) && ((x & (x - 1)) == 0);
}
}
public static class PrimitiveTypeExtensions
{
public static System.Type ConvertToType(this PrimitiveType primitive)
{
switch (primitive)
{
case PrimitiveType.Bool: return typeof(bool);
case PrimitiveType.Void: return typeof(void);
case PrimitiveType.WideChar: return typeof(char);
case PrimitiveType.Int8: return typeof(sbyte);
case PrimitiveType.UInt8: return typeof(byte);
case PrimitiveType.Int16: return typeof(short);
case PrimitiveType.UInt16: return typeof(ushort);
case PrimitiveType.Int32: return typeof(int);
case PrimitiveType.UInt32: return typeof(uint);
case PrimitiveType.Int64: return typeof(long);
case PrimitiveType.UInt64: return typeof(ulong);
case PrimitiveType.Float: return typeof(float);
case PrimitiveType.Double: return typeof(double);
}
return typeof(int);
}
}
public static class StringHelpers
{
public static string CommonPrefix(this string[] ss)
{
if (ss.Length == 0)
{
return "";
}
if (ss.Length == 1)
{
return ss[0];
}
int prefixLength = 0;
foreach (char c in ss[0])
{
foreach (string s in ss)
{
if (s.Length <= prefixLength || s[prefixLength] != c)
{
return ss[0].Substring(0, prefixLength);
}
}
prefixLength++;
}
return ss[0]; // all strings identical
}
/// <summary>
/// Word wraps the given text to fit within the specified width.
/// </summary>
/// <param name="text">Text to be word wrapped</param>
/// <param name="width">Width, in characters, to which the text
/// should be word wrapped</param>
/// <returns>The modified text</returns>
public static List<string> WordWrapLines(string text, int width)
{
int pos, next;
var lines = new List<string>();
// Lucidity check
if (width < 1)
{
lines.Add(text);
return lines;
}
// Parse each line of text
for (pos = 0; pos < text.Length; pos = next)
{
// Find end of line
int eol = text.IndexOf(Environment.NewLine, pos,
System.StringComparison.Ordinal);
if (eol == -1)
next = eol = text.Length;
else
next = eol + Environment.NewLine.Length;
// Copy this line of text, breaking into smaller lines as needed
if (eol > pos)
{
do
{
int len = eol - pos;
if (len > width)
len = BreakLine(text, pos, width);
lines.Add(text.Substring(pos, len));
// Trim whitespace following break
pos += len;
while (pos < eol && Char.IsWhiteSpace(text[pos]))
pos++;
} while (eol > pos);
}
else lines.Add(string.Empty); // Empty line
}
return lines;
}
/// <summary>
/// Locates position to break the given line so as to avoid
/// breaking words.
/// </summary>
/// <param name="text">String that contains line of text</param>
/// <param name="pos">Index where line of text starts</param>
/// <param name="max">Maximum line length</param>
/// <returns>The modified line length</returns>
private static int BreakLine(string text, int pos, int max)
{
// Find last whitespace in line
int i = max;
while (i >= 0 && !Char.IsWhiteSpace(text[pos + i]))
i--;
// If no whitespace found, break at maximum length
if (i < 0)
return max;
// Find start of whitespace
while (i >= 0 && Char.IsWhiteSpace(text[pos + i]))
i--;
// Return length of text before whitespace
return i + 1;
}
public static void CleanupText(ref string debugText)
{
// Strip off newlines from the debug text.
if (String.IsNullOrWhiteSpace(debugText))
debugText = String.Empty;
// TODO: Make this transformation in the output.
debugText = Regex.Replace(debugText, " ( )+", " ");
debugText = Regex.Replace(debugText, "\n", "");
}
}
static class AssemblyHelpers
{
public static IEnumerable<System.Type> FindDerivedTypes(this Assembly assembly,
System.Type baseType)
{
return assembly.GetTypes().Where(baseType.IsAssignableFrom);
}
}
static class Log
{
}
}

3
src/Generator/app.config

@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
<?xml version="1.0"?>
<configuration>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/></startup></configuration>

4
src/Parser/Main.cpp

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@
/************************************************************************
*
* Flush3D <http://www.flush3d.com> © (2008-201x)
* Licensed under the LGPL 2.1 (GNU Lesser General Public License)
* Cxxi
* Licensed under the simplified BSD license. All rights reserved.
*
************************************************************************/

596
src/Parser/Parser.cpp

@ -12,9 +12,9 @@ @@ -12,9 +12,9 @@
#include <clang/Basic/Version.h>
#include <clang/Config/config.h>
#include <clang/AST/ASTContext.h>
#include <clang/AST/DeclTemplate.h>
#include <clang/Lex/HeaderSearch.h>
#include <clang/Lex/PreprocessingRecord.h>
#include <clang/Frontend/HeaderSearchOptions.h>
#include <clang/Frontend/Utils.h>
#include <clang/Driver/Util.h>
@ -49,7 +49,7 @@ static std::string GetClangResourceDir(const std::string& Dir) @@ -49,7 +49,7 @@ static std::string GetClangResourceDir(const std::string& Dir)
static std::string GetClangBuiltinIncludeDir()
{
using namespace llvm;
using namespace llvm;
SmallString<128> P( GetClangResourceDir(".") );
llvm::sys::path::append(P, "include");
@ -78,13 +78,14 @@ void Parser::Setup(ParserOptions^ Opts) @@ -78,13 +78,14 @@ void Parser::Setup(ParserOptions^ Opts)
C->createDiagnostics(ARRAY_SIZE(args), args);
CompilerInvocation* Inv = new CompilerInvocation();
CompilerInvocation::CreateFromArgs(*Inv, args, args + ARRAY_SIZE(args), C->getDiagnostics());
CompilerInvocation::CreateFromArgs(*Inv, args, args + ARRAY_SIZE(args),
C->getDiagnostics());
C->setInvocation(Inv);
TargetOptions& TO = Inv->getTargetOpts();
TO.Triple = llvm::sys::getDefaultTargetTriple();
TargetInfo* TI = TargetInfo::CreateTargetInfo(C->getDiagnostics(), TO);
TargetInfo* TI = TargetInfo::CreateTargetInfo(C->getDiagnostics(), &TO);
TI->setCXXABI(CXXABI_Microsoft);
C->setTarget(TI);
@ -97,7 +98,7 @@ void Parser::Setup(ParserOptions^ Opts) @@ -97,7 +98,7 @@ void Parser::Setup(ParserOptions^ Opts)
for each(System::String^% include in Opts->IncludeDirs)
{
String s = marshalString<E_UTF8>(include);
C->getHeaderSearchOpts().AddPath(s, frontend::Quoted, true, false, true);
C->getHeaderSearchOpts().AddPath(s, frontend::Angled, true, false, true);
}
// Initialize the default platform headers.
@ -107,7 +108,8 @@ void Parser::Setup(ParserOptions^ Opts) @@ -107,7 +108,8 @@ void Parser::Setup(ParserOptions^ Opts)
clang::frontend::System, false, false, true);
#ifdef _WIN32
std::vector<std::string> SystemDirs = clang::driver::GetWindowsSystemIncludeDirs();
std::vector<std::string> SystemDirs
= clang::driver::GetWindowsSystemIncludeDirs();
clang::HeaderSearchOptions& HSOpts = C->getHeaderSearchOpts();
for(size_t i = 0; i < SystemDirs.size(); ++i) {
@ -121,14 +123,16 @@ void Parser::Setup(ParserOptions^ Opts) @@ -121,14 +123,16 @@ void Parser::Setup(ParserOptions^ Opts)
if (C->hasPreprocessor())
{
Preprocessor& P = C->getPreprocessor();
P.createPreprocessingRecord(false /*RecordConditionals*/);
P.getBuiltinInfo().InitializeBuiltins(P.getIdentifierTable(), P.getLangOpts());
//P.createPreprocessingRecord();
P.getBuiltinInfo().InitializeBuiltins(P.getIdentifierTable(),
P.getLangOpts());
}
}
//-----------------------------------//
std::string Parser::GetDeclMangledName(clang::Decl* D, clang::TargetCXXABI ABI)
std::string Parser::GetDeclMangledName(clang::Decl* D, clang::TargetCXXABI ABI,
bool IsDependent)
{
using namespace clang;
@ -138,6 +142,8 @@ std::string Parser::GetDeclMangledName(clang::Decl* D, clang::TargetCXXABI ABI) @@ -138,6 +142,8 @@ std::string Parser::GetDeclMangledName(clang::Decl* D, clang::TargetCXXABI ABI)
bool CanMangle = isa<FunctionDecl>(D) || isa<VarDecl>(D)
|| isa<CXXConstructorDecl>(D) || isa<CXXDestructorDecl>(D);
CanMangle = false;
if (!CanMangle) return "";
NamedDecl* ND = cast<NamedDecl>(D);
@ -161,11 +167,11 @@ std::string Parser::GetDeclMangledName(clang::Decl* D, clang::TargetCXXABI ABI) @@ -161,11 +167,11 @@ std::string Parser::GetDeclMangledName(clang::Decl* D, clang::TargetCXXABI ABI)
std::string Mangled;
llvm::raw_string_ostream Out(Mangled);
if (!MC->shouldMangleDeclName(ND))
{
IdentifierInfo *II = ND->getIdentifier();
return II->getName();
}
if (const ValueDecl *VD = dyn_cast<ValueDecl>(ND))
IsDependent = VD->getType()->isDependentType();
if (!MC->shouldMangleDeclName(ND) || IsDependent)
return ND->getDeclName().getAsString();
if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(ND))
MC->mangleCXXCtor(CD, Ctor_Base, Out);
@ -231,7 +237,7 @@ std::string Parser::GetTypeName(const clang::Type* Type) @@ -231,7 +237,7 @@ std::string Parser::GetTypeName(const clang::Type* Type)
//-----------------------------------//
Cxxi::Class^ Parser::WalkRecordCXX(clang::CXXRecordDecl* Record)
Cxxi::Class^ Parser::WalkRecordCXX(clang::CXXRecordDecl* Record, bool IsDependent)
{
using namespace clang;
using namespace clix;
@ -248,14 +254,32 @@ Cxxi::Class^ Parser::WalkRecordCXX(clang::CXXRecordDecl* Record) @@ -248,14 +254,32 @@ Cxxi::Class^ Parser::WalkRecordCXX(clang::CXXRecordDecl* Record)
return nullptr;
}
if (Record->hasDefinition())
Record = Record->getDefinition();
auto NS = GetNamespace(Record);
auto RC = NS->FindClass(
marshalString<E_UTF8>(GetTagDeclName(Record)), /* Create */ true);
assert(NS && "Expected a valid namespace");
auto Name = marshalString<E_UTF8>(GetTagDeclName(Record));
auto RC = NS->FindClass(Name, /*Create=*/false);
if (RC && !RC->IsIncomplete)
return RC;
if (!RC)
RC = NS->FindClass(Name, /*Create=*/true);
if (!Record->hasDefinition())
{
RC->IsIncomplete = true;
return RC;
}
RC->IsIncomplete = false;
RC->IsPOD = Record->isPOD();
RC->IsUnion = Record->isUnion();
// Get the record layout information.
const ASTRecordLayout& Layout = C->getASTContext().getASTRecordLayout(Record);
RC->IsAbstract = Record->isAbstract();
// Iterate through the record ctors.
for(auto it = Record->ctor_begin(); it != Record->ctor_end(); ++it)
@ -277,13 +301,20 @@ Cxxi::Class^ Parser::WalkRecordCXX(clang::CXXRecordDecl* Record) @@ -277,13 +301,20 @@ Cxxi::Class^ Parser::WalkRecordCXX(clang::CXXRecordDecl* Record)
RC->Methods->Add(Method);
}
// Get the record layout information.
const ASTRecordLayout* Layout = 0;
if (!IsDependent)
Layout = &C->getASTContext().getASTRecordLayout(Record);
// Iterate through the record fields.
for(auto it = Record->field_begin(); it != Record->field_end(); ++it)
{
FieldDecl* FD = (*it);
Cxxi::Field^ Field = WalkFieldCXX(FD);
Field->Offset = Layout.getFieldOffset(FD->getFieldIndex());
if (Layout)
Field->Offset = Layout->getFieldOffset(FD->getFieldIndex());
RC->Fields->Add(Field);
}
@ -295,32 +326,79 @@ Cxxi::Class^ Parser::WalkRecordCXX(clang::CXXRecordDecl* Record) @@ -295,32 +326,79 @@ Cxxi::Class^ Parser::WalkRecordCXX(clang::CXXRecordDecl* Record)
//-----------------------------------//
Cxxi::Method^ Parser::WalkMethodCXX(clang::CXXMethodDecl* Method)
Cxxi::ClassTemplate^ Parser::WalkClassTemplate(clang::ClassTemplateDecl* TD)
{
using namespace clang;
using namespace clix;
DeclarationName MethodName = Method->getDeclName();
auto NS = GetNamespace(TD);
Debug("Method: %s\n", MethodName.getAsString().c_str());
auto Class = WalkRecordCXX(TD->getTemplatedDecl(), /*IsDependent*/true);
Cxxi::ClassTemplate^ CT = gcnew Cxxi::ClassTemplate(Class);
// Write the return type.
QualType Return = Method->getResultType();
return CT;
}
for(auto it = Method->param_begin(); it != Method->param_end(); ++it)
{
ParmVarDecl* Parm = (*it);
//-----------------------------------//
QualType ParmType = Parm->getType();
}
Cxxi::FunctionTemplate^ Parser::WalkFunctionTemplate(clang::FunctionTemplateDecl* TD)
{
using namespace clang;
using namespace clix;
std::string Mangled = GetDeclMangledName(Method, CXXABI_Microsoft);
Debug("\tMangling: %s\n", Mangled.c_str());
auto NS = GetNamespace(TD);
return nullptr;
auto Function = WalkFunction(TD->getTemplatedDecl(), /*IsDependent=*/true);
Cxxi::FunctionTemplate^ FT = gcnew Cxxi::FunctionTemplate(Function);
return FT;
}
//-----------------------------------//
static Cxxi::CXXMethodKind GetMethodKindFromDecl(clang::DeclarationName Name)
{
using namespace clang;
switch(Name.getNameKind())
{
case DeclarationName::Identifier:
case DeclarationName::ObjCZeroArgSelector:
case DeclarationName::ObjCOneArgSelector:
case DeclarationName::ObjCMultiArgSelector:
return Cxxi::CXXMethodKind::Normal;
case DeclarationName::CXXConstructorName:
return Cxxi::CXXMethodKind::Constructor;
case DeclarationName::CXXDestructorName:
return Cxxi::CXXMethodKind::Destructor;
case DeclarationName::CXXConversionFunctionName:
return Cxxi::CXXMethodKind::Conversion;
case DeclarationName::CXXOperatorName:
case DeclarationName::CXXLiteralOperatorName:
return Cxxi::CXXMethodKind::Operator;
case DeclarationName::CXXUsingDirective:
return Cxxi::CXXMethodKind::UsingDirective;
}
return Cxxi::CXXMethodKind::Normal;
}
static Cxxi::CXXOperatorKind GetOperatorKindFromDecl(clang::DeclarationName Name)
{
using namespace clang;
if (Name.getNameKind() != DeclarationName::CXXOperatorName)
return Cxxi::CXXOperatorKind::None;
switch(Name.getCXXOverloadedOperator())
{
#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
case OO_##Name: return Cxxi::CXXOperatorKind::Name;
#include "clang/Basic/OperatorKinds.def"
}
return Cxxi::CXXOperatorKind::None;
}
static Cxxi::AccessSpecifier ConvertToAccess(clang::AccessSpecifier AS)
{
switch(AS)
@ -336,14 +414,51 @@ static Cxxi::AccessSpecifier ConvertToAccess(clang::AccessSpecifier AS) @@ -336,14 +414,51 @@ static Cxxi::AccessSpecifier ConvertToAccess(clang::AccessSpecifier AS)
return Cxxi::AccessSpecifier::Public;
}
Cxxi::Method^ Parser::WalkMethodCXX(clang::CXXMethodDecl* MD)
{
using namespace clang;
DeclarationName Name = MD->getDeclName();
Cxxi::Method^ Method = gcnew Cxxi::Method();
Method->Access = ConvertToAccess(MD->getAccess());
Method->Kind = GetMethodKindFromDecl(Name);
Method->OperatorKind = GetOperatorKindFromDecl(Name);
WalkFunction(MD, Method);
if (const CXXConstructorDecl* CD = dyn_cast<CXXConstructorDecl>(MD))
{
Method->IsDefaultConstructor = CD->isDefaultConstructor();
Method->IsCopyConstructor = CD->isCopyConstructor();
Method->IsMoveConstructor = CD->isMoveConstructor();
}
else if (const CXXDestructorDecl* DD = dyn_cast<CXXDestructorDecl>(MD))
{
}
else if (const CXXConversionDecl* CD = dyn_cast<CXXConversionDecl>(MD))
{
}
return Method;
}
//-----------------------------------//
Cxxi::Field^ Parser::WalkFieldCXX(clang::FieldDecl* FD)
{
using namespace clang;
using namespace clix;
auto NS = GetNamespace(FD);
assert(NS && "Expected a valid namespace");
Cxxi::Field^ F = gcnew Cxxi::Field();
F->Namespace = NS;
F->Name = marshalString<E_UTF8>(FD->getName());
F->Type = WalkType(FD->getType());
auto TL = FD->getTypeSourceInfo()->getTypeLoc();
F->Type = WalkType(FD->getType(), &TL);
F->Access = ConvertToAccess(FD->getAccess());
HandleComments(FD, F);
@ -358,7 +473,8 @@ Cxxi::Namespace^ Parser::GetNamespace(const clang::NamedDecl* ND) @@ -358,7 +473,8 @@ Cxxi::Namespace^ Parser::GetNamespace(const clang::NamedDecl* ND)
using namespace clang;
using namespace clix;
Cxxi::Module^ M = GetModule(ND->getLocation());
SourceLocation Loc = ND->getLocation();
Cxxi::TranslationUnit^ M = GetModule(Loc);
// If the declaration is at global scope, just early exit.
const DeclContext *Ctx = ND->getDeclContext();
@ -389,7 +505,8 @@ Cxxi::Namespace^ Parser::GetNamespace(const clang::NamedDecl* ND) @@ -389,7 +505,8 @@ Cxxi::Namespace^ Parser::GetNamespace(const clang::NamedDecl* ND)
const NamespaceDecl* ND = cast<NamespaceDecl>(Ctx);
if (ND->isAnonymousNamespace())
continue;
NS = NS->FindNamespace(marshalString<E_UTF8>(ND->getName()));
auto Name = marshalString<E_UTF8>(ND->getName());
NS = NS->FindCreateNamespace(Name, NS);
break;
}
case Decl::LinkageSpec:
@ -459,7 +576,8 @@ static Cxxi::PrimitiveType WalkBuiltinType(const clang::BuiltinType* Builtin) @@ -459,7 +576,8 @@ static Cxxi::PrimitiveType WalkBuiltinType(const clang::BuiltinType* Builtin)
//-----------------------------------//
Cxxi::Type^ Parser::WalkType(clang::QualType QualType)
Cxxi::Type^ Parser::WalkType(clang::QualType QualType, clang::TypeLoc* TL,
bool DesugarType)
{
using namespace clang;
using namespace clix;
@ -467,14 +585,16 @@ Cxxi::Type^ Parser::WalkType(clang::QualType QualType) @@ -467,14 +585,16 @@ Cxxi::Type^ Parser::WalkType(clang::QualType QualType)
if (QualType.isNull())
return nullptr;
clang::QualType Desugared = QualType.getDesugaredType(*AST);
const clang::Type* Type = QualType.getTypePtr();
if (Desugared.isNull())
return nullptr;
if (DesugarType)
{
clang::QualType Desugared = QualType.getDesugaredType(*AST);
assert(!Desugared.isNull() && "Expected a valid desugared type");
Type = Desugared.getTypePtr();
}
const clang::Type* Type = QualType.getTypePtr();
assert(Type && "Expected a valid type");
switch(Type->getTypeClass())
{
case Type::Builtin:
@ -490,14 +610,12 @@ Cxxi::Type^ Parser::WalkType(clang::QualType QualType) @@ -490,14 +610,12 @@ Cxxi::Type^ Parser::WalkType(clang::QualType QualType)
case Type::Enum:
{
auto ET = Type->getAs<clang::EnumType>();
const EnumDecl* ED = ET->getDecl();
EnumDecl* ED = ET->getDecl();
// Assume that the type has already been defined for now.
String Name(GetTagDeclName(ED));
auto E = Lib->FindEnum(marshalString<E_UTF8>(Name));
//auto Name = marshalString<E_UTF8>(GetTagDeclName(ED));
auto TT = gcnew Cxxi::TagType();
TT->Declaration = E;
TT->Declaration = WalkDeclaration(ED, 0, /*IgnoreSystemDecls=*/false);
return TT;
}
@ -507,7 +625,9 @@ Cxxi::Type^ Parser::WalkType(clang::QualType QualType) @@ -507,7 +625,9 @@ Cxxi::Type^ Parser::WalkType(clang::QualType QualType)
auto P = gcnew Cxxi::PointerType();
P->Modifier = Cxxi::PointerType::TypeModifier::Pointer;
P->Pointee = WalkType(Pointer->getPointeeType());
auto Next = TL->getNextTypeLoc();
P->Pointee = WalkType(Pointer->getPointeeType(), &Next);
return P;
}
@ -516,6 +636,7 @@ Cxxi::Type^ Parser::WalkType(clang::QualType QualType) @@ -516,6 +636,7 @@ Cxxi::Type^ Parser::WalkType(clang::QualType QualType)
auto TT = Type->getAs<clang::TypedefType>();
TypedefNameDecl* TD = TT->getDecl();
#if 0
auto NS = GetNamespace(TD);
auto TDD = NS->FindTypedef(marshalString<E_UTF8>(GetDeclName(TD)));
@ -523,9 +644,16 @@ Cxxi::Type^ Parser::WalkType(clang::QualType QualType) @@ -523,9 +644,16 @@ Cxxi::Type^ Parser::WalkType(clang::QualType QualType)
// used by the standard library, so we walk the decl to process it.
if (!TDD)
{
TDD = (Cxxi::Typedef^) WalkDeclaration(TD, false);
auto TTL = TD->getTypeSourceInfo()->getTypeLoc();
TDD = (Cxxi::TypedefDecl^) WalkDeclaration(TD, &TTL,
/*IgnoreSystemDecls=*/false);
assert(TDD != nullptr);
}
#endif
auto TTL = TD->getTypeSourceInfo()->getTypeLoc();
auto TDD = safe_cast<Cxxi::TypedefDecl^>(WalkDeclaration(TD, &TTL,
/*IgnoreSystemDecls=*/false));
auto Type = gcnew Cxxi::TypedefType();
Type->Declaration = TDD;
@ -535,39 +663,32 @@ Cxxi::Type^ Parser::WalkType(clang::QualType QualType) @@ -535,39 +663,32 @@ Cxxi::Type^ Parser::WalkType(clang::QualType QualType)
case Type::Elaborated:
{
auto ET = Type->getAs<clang::ElaboratedType>();
return WalkType(ET->getNamedType());
auto Next = TL->getNextTypeLoc();
return WalkType(ET->getNamedType(), &Next);
}
case Type::Record:
{
auto RT = Type->getAs<clang::RecordType>();
const RecordDecl* RD = RT->getDecl();
// Assume that the type has already been defined for now.
String Name(GetTagDeclName(RD));
// We have to try to find the class type. If there is none yet,
// then create it, this is needed to deal properly with forward
// referenced types.
auto NS = GetNamespace(RD);
auto D = NS->FindClass(marshalString<E_UTF8>(Name), true /* Create */);
RecordDecl* RD = RT->getDecl();
auto TT = gcnew Cxxi::TagType();
TT->Declaration = D;
TT->Declaration = WalkDeclaration(RD, 0, /*IgnoreSystemDecls=*/false);
return TT;
}
case Type::Paren:
{
auto PT = Type->getAs<clang::ParenType>();
return WalkType(PT->getInnerType());
auto Next = TL->getNextTypeLoc();
return WalkType(PT->getInnerType(), &Next);
}
case Type::ConstantArray:
{
auto AT = AST->getAsConstantArrayType(QualType);
auto A = gcnew Cxxi::ArrayType();
A->Type = WalkType(AT->getElementType());
auto Next = TL->getNextTypeLoc();
A->Type = WalkType(AT->getElementType(), &Next);
A->SizeType = Cxxi::ArrayType::ArraySize::Constant;
A->Size = AST->getConstantArrayElementCount(AT);
@ -577,11 +698,24 @@ Cxxi::Type^ Parser::WalkType(clang::QualType QualType) @@ -577,11 +698,24 @@ Cxxi::Type^ Parser::WalkType(clang::QualType QualType)
{
auto FP = Type->getAs<clang::FunctionProtoType>();
auto FTL = dyn_cast<FunctionProtoTypeLoc>(TL);
auto RL = FTL->getResultLoc();
auto F = gcnew Cxxi::FunctionType();
F->ReturnType = WalkType(FP->getResultType());
F->ReturnType = WalkType(FP->getResultType(), &RL);
for (unsigned i = 0; i < FP->getNumArgs(); ++i)
F->Arguments->Add(WalkType(FP->getArgType(i)));
{
auto FA = gcnew Cxxi::Parameter();
auto PVD = FTL->getArg(i);
auto PTL = PVD->getTypeSourceInfo()->getTypeLoc();
FA->Name = marshalString<E_UTF8>(PVD->getNameAsString());
FA->Type = WalkType(PVD->getType(), &PTL);
F->Arguments->Add(FA);
}
return F;
}
@ -595,6 +729,131 @@ Cxxi::Type^ Parser::WalkType(clang::QualType QualType) @@ -595,6 +729,131 @@ Cxxi::Type^ Parser::WalkType(clang::QualType QualType)
auto TO = Type->getAs<clang::TypeOfExprType>();
return WalkType(TO->getUnderlyingExpr()->getType());
}
case Type::MemberPointer:
{
auto MP = Type->getAs<clang::MemberPointerType>();
auto Next = TL->getNextTypeLoc();
auto MPT = gcnew Cxxi::MemberPointerType();
MPT->Pointee = WalkType(MP->getPointeeType(), &Next);
return MPT;
}
case Type::TemplateSpecialization:
{
auto TS = Type->getAs<clang::TemplateSpecializationType>();
auto TST = gcnew Cxxi::TemplateSpecializationType();
TemplateName Name = TS->getTemplateName();
TST->Template = safe_cast<Cxxi::Template^>(WalkDeclaration(
Name.getAsTemplateDecl(), 0, /*IgnoreSystemDecls=*/false));
clang::TypeLoc::TypeLocClass Class = TL->getTypeLocClass();
int Loc = (int) Class;
//if (Class != clang::TypeLoc::TemplateSpecialization)
// return TST;
auto TSTL = dyn_cast<TemplateSpecializationTypeLoc>(TL);
for (unsigned I = 0, E = TS->getNumArgs(); I != E; ++I)
{
const TemplateArgument& TA = TS->getArg(I);
auto Arg = Cxxi::TemplateArgument();
TemplateArgumentLoc ArgLoc;
if (Class == clang::TypeLoc::TemplateSpecialization)
ArgLoc = TSTL->getArgLoc(I);
switch(TA.getKind())
{
case TemplateArgument::Type:
{
Arg.Kind = Cxxi::TemplateArgument::ArgumentKind::Type;
TypeLoc ArgTL;
if (Class == clang::TypeLoc::TemplateSpecialization)
ArgTL = ArgLoc.getTypeSourceInfo()->getTypeLoc();
Arg.Type = WalkType(TA.getAsType(), &ArgTL);
break;
}
case TemplateArgument::Declaration:
Arg.Kind = Cxxi::TemplateArgument::ArgumentKind::Declaration;
Arg.Declaration = WalkDeclaration(TA.getAsDecl(), 0);
break;
case TemplateArgument::NullPtr:
Arg.Kind = Cxxi::TemplateArgument::ArgumentKind::NullPtr;
break;
case TemplateArgument::Integral:
Arg.Kind = Cxxi::TemplateArgument::ArgumentKind::Integral;
//Arg.Type = WalkType(TA.getIntegralType(), 0);
Arg.Integral = TA.getAsIntegral().getLimitedValue();
break;
case TemplateArgument::Template:
Arg.Kind = Cxxi::TemplateArgument::ArgumentKind::Template;
break;
case TemplateArgument::TemplateExpansion:
Arg.Kind = Cxxi::TemplateArgument::ArgumentKind::TemplateExpansion;
break;
case TemplateArgument::Expression:
Arg.Kind = Cxxi::TemplateArgument::ArgumentKind::Expression;
break;
case TemplateArgument::Pack:
Arg.Kind = Cxxi::TemplateArgument::ArgumentKind::Pack;
break;
}
TST->Arguments->Add(Arg);
}
return TST;
}
case Type::TemplateTypeParm:
{
auto TP = Type->getAs<TemplateTypeParmType>();
auto TPT = gcnew Cxxi::TemplateParameterType();
//TPT->Parameter = WalkDeclaration(TP->getDecl());
return TPT;
}
case Type::InjectedClassName:
{
auto IN = Type->getAs<InjectedClassNameType>();
return nullptr;
}
case Type::DependentName:
{
auto DN = Type->getAs<DependentNameType>();
return nullptr;
}
case Type::LValueReference:
{
auto LR = Type->getAs<clang::LValueReferenceType>();
auto P = gcnew Cxxi::PointerType();
P->Modifier = Cxxi::PointerType::TypeModifier::LVReference;
TypeLoc Next;
if (!TL->isNull())
Next = TL->getNextTypeLoc();
P->Pointee = WalkType(LR->getPointeeType(), &Next);
return P;
}
case Type::RValueReference:
{
auto LR = Type->getAs<clang::RValueReferenceType>();
auto P = gcnew Cxxi::PointerType();
P->Modifier = Cxxi::PointerType::TypeModifier::RVReference;
TypeLoc Next;
if (!TL->isNull())
Next = TL->getNextTypeLoc();
P->Pointee = WalkType(LR->getPointeeType(), &Next);
return P;
}
default:
{
Debug("Unhandled type class '%s'\n", Type->getTypeClassName());
@ -609,16 +868,34 @@ Cxxi::Enumeration^ Parser::WalkEnum(clang::EnumDecl* ED) @@ -609,16 +868,34 @@ Cxxi::Enumeration^ Parser::WalkEnum(clang::EnumDecl* ED)
using namespace clang;
using namespace clix;
auto E = gcnew Cxxi::Enumeration();
E->Name = marshalString<E_UTF8>(GetTagDeclName(ED));
auto NS = GetNamespace(ED);
assert(NS && "Expected a valid namespace");
auto Name = marshalString<E_UTF8>(GetTagDeclName(ED));
auto E = NS->FindEnum(Name, /*Create=*/false);
if (E && !E->IsIncomplete)
return E;
if (!E)
E = NS->FindEnum(Name, /*Create=*/true);
if (ED->isScoped())
E->Modifiers |= Cxxi::Enumeration::EnumModifiers::Scoped;
// Get the underlying integer backing the enum.
QualType IntType = ED->getIntegerType();
E->Type = safe_cast<Cxxi::BuiltinType^>(WalkType(IntType));
E->Type = WalkType(IntType, 0);
E->BuiltinType = safe_cast<Cxxi::BuiltinType^>(WalkType(IntType, 0,
/*DesugarType=*/true));
if (!ED->isThisDeclarationADefinition())
{
E->IsIncomplete = true;
return E;
}
E->IsIncomplete = false;
for(auto it = ED->enumerator_begin(); it != ED->enumerator_end(); ++it)
{
EnumConstantDecl* ECD = (*it);
@ -641,29 +918,85 @@ Cxxi::Enumeration^ Parser::WalkEnum(clang::EnumDecl* ED) @@ -641,29 +918,85 @@ Cxxi::Enumeration^ Parser::WalkEnum(clang::EnumDecl* ED)
//-----------------------------------//
Cxxi::Function^ Parser::WalkFunction(clang::FunctionDecl* FD)
static Cxxi::CallingConvention ConvertCallConv(clang::CallingConv CC)
{
using namespace clang;
switch(CC)
{
case CC_Default:
case CC_C:
return Cxxi::CallingConvention::C;
case CC_X86StdCall:
return Cxxi::CallingConvention::StdCall;
case CC_X86FastCall:
return Cxxi::CallingConvention::FastCall;
case CC_X86ThisCall:
return Cxxi::CallingConvention::ThisCall;
case CC_X86Pascal:
case CC_AAPCS:
case CC_AAPCS_VFP:
return Cxxi::CallingConvention::Unknown;
}
return Cxxi::CallingConvention::Default;
}
void Parser::WalkFunction(clang::FunctionDecl* FD, Cxxi::Function^ F,
bool IsDependent)
{
using namespace clang;
using namespace clix;
auto F = gcnew Cxxi::Function();
auto FT = FD->getType()->getAs<FunctionType>();
auto CC = FT->getCallConv();
auto NS = GetNamespace(FD);
assert(NS && "Expected a valid namespace");
F->Name = marshalString<E_UTF8>(FD->getNameAsString());
F->Namespace = NS;
F->IsVariadic = FD->isVariadic();
F->IsInline = FD->isInlined();
F->CallingConvention = Cxxi::CallingConvention::Default;
F->ReturnType = WalkType(FD->getResultType());
F->CallingConvention = ConvertCallConv(CC);
TypeLoc RTL;
if (auto TSI = FD->getTypeSourceInfo())
{
TypeLoc TL = TSI->getTypeLoc();
RTL = ((FunctionTypeLoc*) &TL)->getResultLoc();
}
F->ReturnType = WalkType(FD->getResultType(), &RTL);
String Mangled = GetDeclMangledName(FD, CXXABI_Microsoft, IsDependent);
F->Mangled = marshalString<E_UTF8>(Mangled);
for(auto it = FD->param_begin(); it != FD->param_end(); ++it)
{
ParmVarDecl* VD = (*it);
ParmVarDecl* VD = (*it);
auto P = gcnew Cxxi::Parameter();
P->Name = marshalString<E_UTF8>(VD->getNameAsString());
P->IsConst = VD->getType().isConstQualified();
TypeLoc PTL;
if (auto TSI = VD->getTypeSourceInfo())
PTL = VD->getTypeSourceInfo()->getTypeLoc();
P->Type = WalkType(VD->getType(), &PTL);
auto P = gcnew Cxxi::Parameter();
P->Name = marshalString<E_UTF8>(VD->getNameAsString());
P->Type = WalkType(VD->getType());
P->HasDefaultValue = VD->hasDefaultArg();
P->HasDefaultValue = VD->hasDefaultArg();
F->Parameters->Add(P);
F->Parameters->Add(P);
}
}
Cxxi::Function^ Parser::WalkFunction(clang::FunctionDecl* FD, bool IsDependent)
{
using namespace clang;
using namespace clix;
auto F = gcnew Cxxi::Function();
WalkFunction(FD, F, IsDependent);
return F;
}
@ -704,9 +1037,12 @@ void Parser::WalkAST() @@ -704,9 +1037,12 @@ void Parser::WalkAST()
{
Preprocessor& P = C->getPreprocessor();
PreprocessingRecord* PR = P.getPreprocessingRecord();
assert(PR && "Expected a valid preprocessing record");
WalkMacros(PR);
if (PR)
{
assert(PR && "Expected a valid preprocessing record");
WalkMacros(PR);
}
}
TranslationUnitDecl* TU = AST->getTranslationUnitDecl();
@ -720,12 +1056,16 @@ void Parser::WalkAST() @@ -720,12 +1056,16 @@ void Parser::WalkAST()
//-----------------------------------//
Cxxi::Module^ Parser::GetModule(clang::SourceLocation Loc)
Cxxi::TranslationUnit^ Parser::GetModule(clang::SourceLocation Loc)
{
using namespace clang;
using namespace clix;
SourceManager& SM = C->getSourceManager();
if (Loc.isMacroID())
Loc = SM.getExpansionLoc(Loc);
StringRef File = SM.getFilename(Loc);
if (!File.data() || File.empty())
@ -734,7 +1074,11 @@ Cxxi::Module^ Parser::GetModule(clang::SourceLocation Loc) @@ -734,7 +1074,11 @@ Cxxi::Module^ Parser::GetModule(clang::SourceLocation Loc)
return nullptr;
}
return Lib->FindOrCreateModule(marshalString<E_UTF8>(File));
auto Unit = Lib->FindOrCreateModule(marshalString<E_UTF8>(File));
Unit->IsSystemHeader = SM.isInSystemHeader(Loc);
return Unit;
}
//-----------------------------------//
@ -755,7 +1099,7 @@ void Parser::WalkMacros(clang::PreprocessingRecord* PR) @@ -755,7 +1099,7 @@ void Parser::WalkMacros(clang::PreprocessingRecord* PR)
case PreprocessedEntity::MacroDefinitionKind:
{
const MacroDefinition* MD = cast<MacroDefinition>(PE);
if (!IsValidDeclaration(MD->getLocation()))
break;
@ -782,12 +1126,13 @@ void Parser::WalkMacros(clang::PreprocessingRecord* PR) @@ -782,12 +1126,13 @@ void Parser::WalkMacros(clang::PreprocessingRecord* PR)
BeginExpr, MI->getDefinitionEndLoc());
bool Invalid;
StringRef Expression = Lexer::getSourceText(Range, SM, LangOpts, &Invalid);
StringRef Expression = Lexer::getSourceText(Range, SM, LangOpts,
&Invalid);
if (Invalid || Expression.empty())
break;
auto macro = gcnew Cxxi::MacroDefine();
auto macro = gcnew Cxxi::MacroDefinition();
macro->Name = marshalString<E_UTF8>(II->getName())->Trim();
macro->Expression = marshalString<E_UTF8>(Expression)->Trim();
@ -822,35 +1167,25 @@ void Parser::HandleComments(clang::Decl* D, Cxxi::Declaration^ Decl) @@ -822,35 +1167,25 @@ void Parser::HandleComments(clang::Decl* D, Cxxi::Declaration^ Decl)
bool Invalid;
StringRef DeclText = Lexer::getSourceText(Range, SM, LangOpts, &Invalid);
assert(!Invalid && "Should have a valid location");
Decl->DebugText = marshalString<E_UTF8>(DeclText);
//assert(!Invalid && "Should have a valid location");
if (!Invalid)
Decl->DebugText = marshalString<E_UTF8>(DeclText);
}
//-----------------------------------//
Cxxi::Declaration^ Parser::WalkDeclaration(clang::Decl* D, bool ignoreSystemDecls)
Cxxi::Declaration^ Parser::WalkDeclaration(clang::Decl* D,
clang::TypeLoc* TL, bool IgnoreSystemDecls)
{
using namespace clang;
using namespace clix;
// Ignore declarations that do not come from user-provided
// header files.
if (ignoreSystemDecls && !IsValidDeclaration(D->getLocation()))
if (IgnoreSystemDecls && !IsValidDeclaration(D->getLocation()))
return nullptr;
if(NamedDecl* ND = dyn_cast<NamedDecl>(D))
{
const char* KindName = D->getDeclKindName();
DeclarationName DN = ND->getDeclName();
std::string DeclName = DN.getAsString();
//Debug("(%s) %s\n", KindName, DeclName.c_str());
std::string Mangled = GetDeclMangledName(ND, CXXABI_Microsoft);
}
for(auto it = D->attr_begin(); it != D->attr_end(); ++it)
{
Attr* Attr = (*it);
@ -866,39 +1201,53 @@ Cxxi::Declaration^ Parser::WalkDeclaration(clang::Decl* D, bool ignoreSystemDecl @@ -866,39 +1201,53 @@ Cxxi::Declaration^ Parser::WalkDeclaration(clang::Decl* D, bool ignoreSystemDecl
Cxxi::Declaration^ Decl;
auto Kind = D->getKind();
switch(D->getKind())
{
case Decl::CXXRecord:
{
CXXRecordDecl* RD = cast<CXXRecordDecl>(D);
if (!RD->isThisDeclarationADefinition())
break;
auto Class = WalkRecordCXX(RD);
HandleComments(RD, Class);
auto NS = GetNamespace(RD);
auto RC = NS->FindClass(marshalString<E_UTF8>(GetTagDeclName(RD)), /* Create */ false);
Decl = Class;
break;
}
case Decl::ClassTemplate:
{
ClassTemplateDecl* TD = cast<ClassTemplateDecl>(D);
auto Template = WalkClassTemplate(TD);
if (!RC)
NS->Classes->Add(Class);
auto NS = GetNamespace(TD);
Template->Namespace = NS;
NS->Templates->Add(Template);
Decl = Class;
Decl = Template;
break;
}
case Decl::FunctionTemplate:
{
FunctionTemplateDecl* TD = cast<FunctionTemplateDecl>(D);
auto Template = WalkFunctionTemplate(TD);
auto NS = GetNamespace(TD);
Template->Namespace = NS;
NS->Templates->Add(Template);
Decl = Template;
break;
}
case Decl::Enum:
{
EnumDecl* ED = cast<EnumDecl>(D);
if (!ED->isThisDeclarationADefinition())
break;
auto E = WalkEnum(ED);
HandleComments(ED, E);
auto NS = GetNamespace(ED);
NS->Enums->Add(E);
Decl = E;
break;
@ -913,6 +1262,7 @@ Cxxi::Declaration^ Parser::WalkDeclaration(clang::Decl* D, bool ignoreSystemDecl @@ -913,6 +1262,7 @@ Cxxi::Declaration^ Parser::WalkDeclaration(clang::Decl* D, bool ignoreSystemDecl
HandleComments(FD, F);
auto NS = GetNamespace(FD);
F->Namespace = NS;
NS->Functions->Add(F);
Decl = F;
@ -934,14 +1284,16 @@ Cxxi::Declaration^ Parser::WalkDeclaration(clang::Decl* D, bool ignoreSystemDecl @@ -934,14 +1284,16 @@ Cxxi::Declaration^ Parser::WalkDeclaration(clang::Decl* D, bool ignoreSystemDecl
case Decl::Typedef:
{
TypedefDecl* TD = cast<TypedefDecl>(D);
const QualType& Type = TD->getUnderlyingType();
auto Typedef = gcnew Cxxi::Typedef();
Typedef->Name = marshalString<E_UTF8>(GetDeclName(TD));
Typedef->Type = WalkType(Type);
auto NS = GetNamespace(TD);
NS->Typedefs->Add(Typedef);
auto Name = marshalString<E_UTF8>(GetDeclName(TD));
auto Typedef = NS->FindTypedef(Name, /*Create=*/false);
if (Typedef) return Typedef;
Typedef = NS->FindTypedef(Name, /*Create=*/true);
auto TTL = TD->getTypeSourceInfo()->getTypeLoc();
Typedef->Type = WalkType(TD->getUnderlyingType(), &TTL);
Decl = Typedef;

20
src/Parser/Parser.h

@ -63,22 +63,28 @@ protected: @@ -63,22 +63,28 @@ protected:
void WalkAST();
void WalkMacros(clang::PreprocessingRecord* PR);
Cxxi::Declaration^ WalkDeclaration(clang::Decl* D,
bool IgnoreSystemDecls = true);
clang::TypeLoc* = 0, bool IgnoreSystemDecls = true);
Cxxi::Enumeration^ WalkEnum(clang::EnumDecl*);
Cxxi::Function^ WalkFunction(clang::FunctionDecl*);
Cxxi::Class^ WalkRecordCXX(clang::CXXRecordDecl*);
Cxxi::Function^ WalkFunction(clang::FunctionDecl*, bool IsDependent = false);
Cxxi::Class^ WalkRecordCXX(clang::CXXRecordDecl*, bool IsDependent = false);
Cxxi::Method^ WalkMethodCXX(clang::CXXMethodDecl*);
Cxxi::Field^ WalkFieldCXX(clang::FieldDecl*);
Cxxi::Type^ WalkType(clang::QualType QualType);
Cxxi::ClassTemplate^ Parser::WalkClassTemplate(clang::ClassTemplateDecl*);
Cxxi::FunctionTemplate^ Parser::WalkFunctionTemplate(
clang::FunctionTemplateDecl*);
Cxxi::Type^ WalkType(clang::QualType, clang::TypeLoc* = 0,
bool DesugarType = false);
// Clang helpers
bool IsValidDeclaration(const clang::SourceLocation& Loc);
std::string GetDeclMangledName(clang::Decl*, clang::TargetCXXABI);
std::string GetDeclMangledName(clang::Decl*, clang::TargetCXXABI,
bool IsDependent = false);
std::string GetTypeName(const clang::Type*);
void HandleComments(clang::Decl* D, Cxxi::Declaration^);
void WalkFunction(clang::FunctionDecl* FD, Cxxi::Function^ F,
bool IsDependent = false);
Cxxi::Module^ GetModule(clang::SourceLocation Loc);
Cxxi::TranslationUnit^ GetModule(clang::SourceLocation Loc);
Cxxi::Namespace^ GetNamespace(const clang::NamedDecl*);
gcroot<Cxxi::Library^> Lib;

Loading…
Cancel
Save