├── .gitattributes ├── .gitignore ├── CS_2_C.sln ├── CS_2_C ├── App.config ├── CS_2_C.csproj ├── Program.cs ├── Properties │ └── AssemblyInfo.cs └── packages.config ├── LICENSE └── LibCS2C ├── Attributes ├── Extern.cs └── Plug.cs ├── Compilation ├── Compiler.cs ├── CompilerSettings.cs └── SyntaxWalker.cs ├── Context ├── GenericTypeConversion.cs ├── MethodTable.cs ├── TypeConversion.cs ├── WalkerContext.cs ├── Writer.cs └── WriterDestination.cs ├── Generators ├── AddressOfExpressionGenerator.cs ├── AllGenerators.cs ├── ArgumentListGenerator.cs ├── ArrayCreationExpressionGenerator.cs ├── ArrayInitializerGenerator.cs ├── AssignmentGenerator.cs ├── BlockGenerator.cs ├── CastExpressionGenerator.cs ├── ClassCctorGenerator.cs ├── ClassCode.cs ├── ClassCodeGenerator.cs ├── ClassInitGenerator.cs ├── ClassStaticStructGenerator.cs ├── ClassStructGenerator.cs ├── ConditionalAccessExpressionGenerator.cs ├── DelegateDeclarationGenerator.cs ├── DoStatementGenerator.cs ├── ElementAccessGenerator.cs ├── EnumGenerator.cs ├── ExpressionGenerator.cs ├── ExpressionStatementGenerator.cs ├── FixedStatementGenerator.cs ├── ForStatementGenerator.cs ├── GeneratorBase.cs ├── GotoStatementGenerator.cs ├── IGenerator.cs ├── IdentifierNameGenerator.cs ├── IfStatementGenerator.cs ├── InterfaceGenerator.cs ├── InvocationGenerator.cs ├── LabeledStatementGenerator.cs ├── LocalDeclarationGenerator.cs ├── MethodGenerator.cs ├── ObjectCreationExpressionGenerator.cs ├── PointerMemberAccessGenerator.cs ├── PrePostExpressionGenerator.cs ├── PropertyGenerator.cs ├── ReturnStatementGenerator.cs ├── SimpleAssignmentGenerator.cs ├── SimpleMemberAccessGenerator.cs ├── SizeofExpressionGenerator.cs ├── StructGenerator.cs ├── SwitchStatementGenerator.cs ├── UncheckedStatementGenerator.cs ├── VariableGenerator.cs └── WhileStatementGenerator.cs ├── LibCS2C.csproj ├── Properties └── AssemblyInfo.cs ├── Tasks └── CompileProjectTask.cs ├── Util └── FormattedStringBuilder.cs └── packages.config /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | build/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | out/ 25 | 26 | # Visual Studio 2015 cache/options directory 27 | .vs/ 28 | 29 | # MSTest test Results 30 | [Tt]est[Rr]esult*/ 31 | [Bb]uild[Ll]og.* 32 | 33 | # NUNIT 34 | *.VisualState.xml 35 | TestResult.xml 36 | 37 | # Build Results of an ATL Project 38 | [Dd]ebugPS/ 39 | [Rr]eleasePS/ 40 | dlldata.c 41 | 42 | # DNX 43 | project.lock.json 44 | artifacts/ 45 | 46 | *_i.c 47 | *_p.c 48 | *_i.h 49 | *.ilk 50 | *.meta 51 | *.obj 52 | *.pch 53 | *.pdb 54 | *.pgc 55 | *.pgd 56 | *.rsp 57 | *.sbr 58 | *.tlb 59 | *.tli 60 | *.tlh 61 | *.tmp 62 | *.tmp_proj 63 | *.log 64 | *.vspscc 65 | *.vssscc 66 | .builds 67 | *.pidb 68 | *.svclog 69 | *.scc 70 | 71 | # Chutzpah Test files 72 | _Chutzpah* 73 | 74 | # Visual C++ cache files 75 | ipch/ 76 | *.aps 77 | *.ncb 78 | *.opensdf 79 | *.sdf 80 | *.cachefile 81 | 82 | # Visual Studio profiler 83 | *.psess 84 | *.vsp 85 | *.vspx 86 | 87 | # TFS 2012 Local Workspace 88 | $tf/ 89 | 90 | # Guidance Automation Toolkit 91 | *.gpState 92 | 93 | # ReSharper is a .NET coding add-in 94 | _ReSharper*/ 95 | *.[Rr]e[Ss]harper 96 | *.DotSettings.user 97 | 98 | # JustCode is a .NET coding add-in 99 | .JustCode 100 | 101 | # TeamCity is a build add-in 102 | _TeamCity* 103 | 104 | # DotCover is a Code Coverage Tool 105 | *.dotCover 106 | 107 | # NCrunch 108 | _NCrunch_* 109 | .*crunch*.local.xml 110 | 111 | # MightyMoose 112 | *.mm.* 113 | AutoTest.Net/ 114 | 115 | # Web workbench (sass) 116 | .sass-cache/ 117 | 118 | # Installshield output folder 119 | [Ee]xpress/ 120 | 121 | # DocProject is a documentation generator add-in 122 | DocProject/buildhelp/ 123 | DocProject/Help/*.HxT 124 | DocProject/Help/*.HxC 125 | DocProject/Help/*.hhc 126 | DocProject/Help/*.hhk 127 | DocProject/Help/*.hhp 128 | DocProject/Help/Html2 129 | DocProject/Help/html 130 | 131 | # Click-Once directory 132 | publish/ 133 | 134 | # Publish Web Output 135 | *.[Pp]ublish.xml 136 | *.azurePubxml 137 | ## TODO: Comment the next line if you want to checkin your 138 | ## web deploy settings but do note that will include unencrypted 139 | ## passwords 140 | #*.pubxml 141 | 142 | *.publishproj 143 | 144 | # NuGet Packages 145 | *.nupkg 146 | # The packages folder can be ignored because of Package Restore 147 | **/packages/* 148 | # except build/, which is used as an MSBuild target. 149 | !**/packages/build/ 150 | # Uncomment if necessary however generally it will be regenerated when needed 151 | #!**/packages/repositories.config 152 | 153 | # Windows Azure Build Output 154 | csx/ 155 | *.build.csdef 156 | 157 | # Windows Store app package directory 158 | AppPackages/ 159 | 160 | # Visual Studio cache files 161 | # files ending in .cache can be ignored 162 | *.[Cc]ache 163 | # but keep track of directories ending in .cache 164 | !*.[Cc]ache/ 165 | 166 | # Others 167 | ClientBin/ 168 | [Ss]tyle[Cc]op.* 169 | ~$* 170 | *~ 171 | *.dbmdl 172 | *.dbproj.schemaview 173 | *.pfx 174 | *.publishsettings 175 | node_modules/ 176 | orleans.codegen.cs 177 | 178 | # RIA/Silverlight projects 179 | Generated_Code/ 180 | 181 | # Backup & report files from converting an old project file 182 | # to a newer Visual Studio version. Backup files are not needed, 183 | # because we have git ;-) 184 | _UpgradeReport_Files/ 185 | Backup*/ 186 | UpgradeLog*.XML 187 | UpgradeLog*.htm 188 | 189 | # SQL Server files 190 | *.mdf 191 | *.ldf 192 | 193 | # Business Intelligence projects 194 | *.rdl.data 195 | *.bim.layout 196 | *.bim_*.settings 197 | 198 | # Microsoft Fakes 199 | FakesAssemblies/ 200 | 201 | # Node.js Tools for Visual Studio 202 | .ntvs_analysis.dat 203 | 204 | # Visual Studio 6 build log 205 | *.plg 206 | 207 | # Visual Studio 6 workspace options file 208 | *.opt 209 | 210 | # LightSwitch generated files 211 | GeneratedArtifacts/ 212 | _Pvt_Extensions/ 213 | ModelManifest.xml 214 | *.opendb 215 | *.db 216 | -------------------------------------------------------------------------------- /CS_2_C.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25420.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CS_2_C", "CS_2_C\CS_2_C.csproj", "{70D5D661-B4B4-46C5-A67E-D20F1EFD36B7}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LibCS2C", "LibCS2C\LibCS2C.csproj", "{12C65AF1-DF61-4105-AD57-8369A928D2E1}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {70D5D661-B4B4-46C5-A67E-D20F1EFD36B7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {70D5D661-B4B4-46C5-A67E-D20F1EFD36B7}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {70D5D661-B4B4-46C5-A67E-D20F1EFD36B7}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {70D5D661-B4B4-46C5-A67E-D20F1EFD36B7}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {12C65AF1-DF61-4105-AD57-8369A928D2E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {12C65AF1-DF61-4105-AD57-8369A928D2E1}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {12C65AF1-DF61-4105-AD57-8369A928D2E1}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {12C65AF1-DF61-4105-AD57-8369A928D2E1}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /CS_2_C/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /CS_2_C/CS_2_C.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {70D5D661-B4B4-46C5-A67E-D20F1EFD36B7} 8 | Exe 9 | Properties 10 | CS_2_C 11 | CS_2_C 12 | v4.5.2 13 | 512 14 | true 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | AnyCPU 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | 37 | ..\packages\Microsoft.CodeAnalysis.Common.1.2.2\lib\net45\Microsoft.CodeAnalysis.dll 38 | True 39 | 40 | 41 | ..\packages\Microsoft.CodeAnalysis.CSharp.1.2.2\lib\net45\Microsoft.CodeAnalysis.CSharp.dll 42 | True 43 | 44 | 45 | ..\packages\Microsoft.CodeAnalysis.CSharp.Workspaces.1.2.2\lib\net45\Microsoft.CodeAnalysis.CSharp.Workspaces.dll 46 | True 47 | 48 | 49 | ..\packages\Microsoft.CodeAnalysis.VisualBasic.1.2.2\lib\net45\Microsoft.CodeAnalysis.VisualBasic.dll 50 | True 51 | 52 | 53 | ..\packages\Microsoft.CodeAnalysis.VisualBasic.Workspaces.1.2.2\lib\net45\Microsoft.CodeAnalysis.VisualBasic.Workspaces.dll 54 | True 55 | 56 | 57 | ..\packages\Microsoft.CodeAnalysis.Workspaces.Common.1.2.2\lib\net45\Microsoft.CodeAnalysis.Workspaces.dll 58 | True 59 | 60 | 61 | ..\packages\Microsoft.CodeAnalysis.Workspaces.Common.1.2.2\lib\net45\Microsoft.CodeAnalysis.Workspaces.Desktop.dll 62 | True 63 | 64 | 65 | 66 | ..\packages\System.Collections.Immutable.1.1.37\lib\dotnet\System.Collections.Immutable.dll 67 | True 68 | 69 | 70 | ..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.AttributedModel.dll 71 | True 72 | 73 | 74 | ..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.Convention.dll 75 | True 76 | 77 | 78 | ..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.Hosting.dll 79 | True 80 | 81 | 82 | ..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.Runtime.dll 83 | True 84 | 85 | 86 | ..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.TypedParts.dll 87 | True 88 | 89 | 90 | 91 | ..\packages\System.Reflection.Metadata.1.2.0\lib\portable-net45+win8\System.Reflection.Metadata.dll 92 | True 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | {12c65af1-df61-4105-ad57-8369a928d2e1} 116 | LibCS2C 117 | 118 | 119 | 120 | 127 | -------------------------------------------------------------------------------- /CS_2_C/Program.cs: -------------------------------------------------------------------------------- 1 | using LibCS2C.Compilation; 2 | using System; 3 | 4 | namespace CS_2_C 5 | { 6 | class Program 7 | { 8 | /// 9 | /// Entrypoint of the quick testing the compiler 10 | /// 11 | /// 12 | static void Main(string[] args) 13 | { 14 | Compiler compiler = new Compiler(); 15 | // compiler.CompileProject(@"C:\Users\jeffr\Documents\visual studio 2015\Projects\Sharpen\kernel\Sharpen\Sharpen.csproj", ""); 16 | compiler.CompileProject(@"C:\Users\Niels\Documents\Sharpen\kernel\Sharpen\Sharpen.csproj", ""); 17 | compiler.CreateHeaderFile("output.h", new string[0]); 18 | compiler.CreateSourceFile("output.c", new string[] { "output.h" }); 19 | Console.ReadLine(); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /CS_2_C/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("CS_2_C")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("CS_2_C")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("70d5d661-b4b4-46c5-a67e-d20f1efd36b7")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /CS_2_C/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /LibCS2C/Attributes/Extern.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace LibCS2C.Attributes 4 | { 5 | [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)] 6 | public class Extern : Attribute 7 | { 8 | public string ExternalName { get; private set; } 9 | public bool CreatePrototype { get; private set; } 10 | 11 | /// 12 | /// Initializes a new external method reference 13 | /// 14 | /// The name of the external method reference 15 | /// If we need to create a prototype 16 | public Extern(string externalName, bool createPrototype = false) 17 | { 18 | ExternalName = externalName; 19 | CreatePrototype = createPrototype; 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /LibCS2C/Attributes/Plug.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace LibCS2C.Attributes 4 | { 5 | [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)] 6 | public class Plug : Attribute 7 | { 8 | public string OverrideName { get; private set; } 9 | 10 | /// 11 | /// Initializes a new plug 12 | /// 13 | /// The name of the method to override 14 | public Plug(string overrideName) 15 | { 16 | OverrideName = overrideName; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /LibCS2C/Compilation/Compiler.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.CodeAnalysis; 2 | using Microsoft.CodeAnalysis.MSBuild; 3 | using System; 4 | using System.IO; 5 | using System.Text; 6 | 7 | namespace LibCS2C.Compilation 8 | { 9 | public class Compiler 10 | { 11 | public string CurrentProjectName { get; private set; } 12 | public string CurrentDocumentName { get; private set; } 13 | 14 | private StringBuilder m_headerCode; 15 | private StringBuilder m_sourceCode; 16 | 17 | /// 18 | /// Compiles a project 19 | /// 20 | /// The project path 21 | /// The suffix to the init method 22 | public void CompileProject(string projectPath, string initSuffix) 23 | { 24 | // Workspace to open project 25 | MSBuildWorkspace workspace = MSBuildWorkspace.Create(); 26 | Project project = workspace.OpenProjectAsync(projectPath).Result; 27 | CurrentProjectName = project.Name; 28 | 29 | Console.WriteLine("Project name: " + CurrentProjectName); 30 | Console.WriteLine("-------------"); 31 | 32 | // Buffer that holds all the output code 33 | SyntaxWalker walker = new SyntaxWalker(initSuffix); 34 | 35 | // Loop through each file of the project 36 | foreach (Document document in project.Documents) 37 | { 38 | CurrentDocumentName = document.Name; 39 | Console.WriteLine("Process file: " + CurrentDocumentName); 40 | 41 | walker.SetDocument(document); 42 | 43 | // Go through the syntax tree and convert the code 44 | SyntaxTree tree = document.GetSyntaxTreeAsync().Result; 45 | SyntaxNode node = tree.GetRoot(); 46 | walker.Visit(node); 47 | } 48 | 49 | m_headerCode = walker.GetHeaderCode(); 50 | m_sourceCode = walker.GetSourceCode(); 51 | } 52 | 53 | /// 54 | /// Ensures that a directory exists 55 | /// 56 | /// The path 57 | private void ensureDirectoryExists(string path) 58 | { 59 | string outDir = Path.GetDirectoryName(path); 60 | if (outDir.Length == 0) 61 | return; 62 | 63 | if (!Directory.Exists(outDir)) 64 | Directory.CreateDirectory(outDir); 65 | } 66 | 67 | /// 68 | /// Writes a code file 69 | /// 70 | /// The StringBuilder containing the code 71 | /// The filename 72 | /// the headers to include 73 | private void writeCodeFile(StringBuilder sb, string filename, string[] includeHeaders) 74 | { 75 | if (sb == null) 76 | throw new Exception("Code is not compiled yet!"); 77 | 78 | ensureDirectoryExists(filename); 79 | 80 | // Write contents 81 | StreamWriter stream = new StreamWriter(filename, false); 82 | 83 | // Additional header files to include 84 | foreach (string file in includeHeaders) 85 | { 86 | stream.WriteLine(string.Format("#include \"{0}\"", file)); 87 | } 88 | 89 | // The output code itself 90 | stream.Write(sb.ToString()); 91 | 92 | stream.Close(); 93 | } 94 | 95 | /// 96 | /// Creates the header file 97 | /// 98 | /// The header filename 99 | /// What headers to include 100 | public void CreateHeaderFile(string filename, string[] includeHeaders) 101 | { 102 | writeCodeFile(m_headerCode, filename, includeHeaders); 103 | } 104 | 105 | /// 106 | /// Creates the source file 107 | /// 108 | /// The source filename 109 | /// What headers to include 110 | public void CreateSourceFile(string filename, string[] includeHeaders) 111 | { 112 | writeCodeFile(m_sourceCode, filename, includeHeaders); 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /LibCS2C/Compilation/CompilerSettings.cs: -------------------------------------------------------------------------------- 1 | namespace LibCS2C.Compilation 2 | { 3 | class CompilerSettings 4 | { 5 | // Compiler flags 6 | public static bool EnableRuntimeChecks { get; set; } = true; 7 | 8 | // Error messages name 9 | public const string RuntimeErrorNullCalledName = "__ERROR_NULL_CALLED__"; 10 | 11 | // Error message 12 | public const string RuntimeErrorNullCalled = "The program tried to call a method of an object that is null"; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /LibCS2C/Compilation/SyntaxWalker.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | using Microsoft.CodeAnalysis; 3 | using Microsoft.CodeAnalysis.CSharp; 4 | using Microsoft.CodeAnalysis.CSharp.Syntax; 5 | using LibCS2C.Context; 6 | 7 | namespace LibCS2C.Compilation 8 | { 9 | public class SyntaxWalker : CSharpSyntaxWalker 10 | { 11 | private WalkerContext m_context; 12 | private string m_initSuffix; 13 | 14 | /// 15 | /// Walks through the syntax and outputs C code to a string 16 | /// 17 | public SyntaxWalker(string initSuffix) : base(SyntaxWalkerDepth.Node) 18 | { 19 | m_context = new WalkerContext(); 20 | m_initSuffix = initSuffix; 21 | } 22 | 23 | /// 24 | /// Sets the current document 25 | /// 26 | /// The document 27 | public void SetDocument(Document doc) 28 | { 29 | m_context.Model = doc.GetSemanticModelAsync().Result; 30 | } 31 | 32 | /// 33 | /// Visits a struct declaration 34 | /// 35 | /// The struct declaration node 36 | public override void VisitStructDeclaration(StructDeclarationSyntax node) 37 | { 38 | m_context.Writer.CurrentDestination = WriterDestination.Structs; 39 | m_context.Generators.Struct.Generate(node); 40 | base.VisitStructDeclaration(node); 41 | } 42 | 43 | /// 44 | /// Visits a class declaration 45 | /// 46 | /// The class declaration node 47 | public override void VisitClassDeclaration(ClassDeclarationSyntax node) 48 | { 49 | m_context.CurrentClass = node; 50 | m_context.MethodTable.AddCurrentClass(); 51 | m_context.Generators.ClassCode.Generate(node); 52 | base.VisitClassDeclaration(node); 53 | } 54 | 55 | /// 56 | /// Visits an interface declaration 57 | /// 58 | /// The interface declaration node 59 | public override void VisitInterfaceDeclaration(InterfaceDeclarationSyntax node) 60 | { 61 | m_context.Generators.Interface.Generate(node); 62 | base.VisitInterfaceDeclaration(node); 63 | } 64 | 65 | /// 66 | /// Visit a constructor declaration 67 | /// 68 | /// The constructor declaration node 69 | public override void VisitConstructorDeclaration(ConstructorDeclarationSyntax node) 70 | { 71 | m_context.Generators.MethodDeclaration.Generate(node); 72 | base.VisitConstructorDeclaration(node); 73 | } 74 | 75 | /// 76 | /// Visits a method declaration 77 | /// 78 | /// The method declaration node 79 | public override void VisitMethodDeclaration(MethodDeclarationSyntax node) 80 | { 81 | m_context.Generators.MethodDeclaration.Generate(node); 82 | base.VisitMethodDeclaration(node); 83 | } 84 | 85 | /// 86 | /// Visits a property declaration 87 | /// 88 | /// The property node 89 | public override void VisitPropertyDeclaration(PropertyDeclarationSyntax node) 90 | { 91 | m_context.Generators.Property.Generate(node); 92 | base.VisitPropertyDeclaration(node); 93 | } 94 | 95 | /// 96 | /// Visits an enum declaration 97 | /// 98 | /// The enum node 99 | public override void VisitEnumDeclaration(EnumDeclarationSyntax node) 100 | { 101 | m_context.Generators.Enum.Generate(node); 102 | base.VisitEnumDeclaration(node); 103 | } 104 | 105 | /// 106 | /// Visits a namespace declaration 107 | /// 108 | /// The namespace declaration node 109 | public override void VisitNamespaceDeclaration(NamespaceDeclarationSyntax node) 110 | { 111 | m_context.CurrentNamespace = node; 112 | base.VisitNamespaceDeclaration(node); 113 | } 114 | 115 | /// 116 | /// Visits a delegate declaration 117 | /// 118 | /// The delegate declaration node 119 | public override void VisitDelegateDeclaration(DelegateDeclarationSyntax node) 120 | { 121 | m_context.Generators.DelegateDeclaration.Generate(node); 122 | base.VisitDelegateDeclaration(node); 123 | } 124 | 125 | /// 126 | /// Generates the header code 127 | /// 128 | /// The header 129 | public StringBuilder GetHeaderCode() 130 | { 131 | StringBuilder sb = new StringBuilder(); 132 | 133 | sb.AppendLine("#ifndef __TYPES_DEFINED__"); 134 | sb.AppendLine("#define __TYPES_DEFINED__"); 135 | 136 | // Error message 137 | string[][] errors = 138 | { 139 | new string[] { CompilerSettings.RuntimeErrorNullCalledName, CompilerSettings.RuntimeErrorNullCalled } 140 | }; 141 | foreach (string[] error in errors) 142 | { 143 | sb.AppendLine(string.Format("const static char* {0} = \"{1}\";", error)); 144 | } 145 | 146 | // Types 147 | string[][] types = 148 | { 149 | new string[]{ "action_t", "void*" }, 150 | new string[]{ "object_t", "void*" }, 151 | new string[]{ "bool_t", "int32_t" }, 152 | new string[]{ "string_t", "char*" } 153 | }; 154 | foreach (string[] type in types) 155 | { 156 | sb.AppendLine(string.Format("typedef {1} {0};", type)); 157 | } 158 | 159 | // Default class 160 | sb.AppendLine("struct base_class"); 161 | sb.AppendLine("{"); 162 | sb.AppendLine("\tvoid** lookup_table;"); 163 | sb.AppendLine("};"); 164 | 165 | sb.AppendLine("#endif"); 166 | 167 | // .cctor prototype 168 | sb.AppendLine(string.Format("void init{0}(void);", m_initSuffix)); 169 | 170 | // Code 171 | sb.AppendLine(m_context.Writer.SbEnums.ToString()); 172 | sb.AppendLine(m_context.Writer.SbStructPrototypes.ToString()); 173 | sb.AppendLine(m_context.Writer.SbDelegates.ToString()); 174 | sb.AppendLine(m_context.Writer.SbStructs.ToString()); 175 | sb.AppendLine(m_context.Writer.SbClassStructs.ToString()); 176 | sb.AppendLine(m_context.Writer.SbMethodPrototypes.ToString()); 177 | sb.AppendLine(m_context.MethodTable.ToPrototypeArrayCode()); 178 | 179 | return sb; 180 | } 181 | 182 | /// 183 | /// Outputs the source code 184 | /// 185 | /// The source code 186 | public StringBuilder GetSourceCode() 187 | { 188 | StringBuilder sb = new StringBuilder(); 189 | 190 | sb.AppendLine(m_context.Writer.SbMethodDeclarations.ToString()); 191 | sb.AppendLine(m_context.MethodTable.ToArrayCode()); 192 | 193 | // Add .cctor calls in init method 194 | sb.AppendLine(string.Format("void init{0}(void)", m_initSuffix)); 195 | sb.AppendLine("{"); 196 | foreach (string cctor in m_context.CctorList) 197 | { 198 | sb.AppendLine("\t" + cctor + "();"); 199 | } 200 | sb.AppendLine("}"); 201 | 202 | return sb; 203 | } 204 | } 205 | } 206 | -------------------------------------------------------------------------------- /LibCS2C/Context/GenericTypeConversion.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.CodeAnalysis; 2 | using Microsoft.CodeAnalysis.CSharp.Syntax; 3 | using System; 4 | using System.Collections.Generic; 5 | 6 | namespace LibCS2C.Context 7 | { 8 | /// 9 | /// Contains the native / generic type conversions 10 | /// 11 | public class GenericTypeConversion 12 | { 13 | private Dictionary m_convert = new Dictionary() 14 | { 15 | { "void", "void" }, 16 | 17 | { "bool", "bool_t" }, 18 | { "long", "int64_t" }, 19 | { "ulong", "uint64_t" }, 20 | { "int", "int32_t" }, 21 | { "uint", "uint32_t" }, 22 | { "short", "int16_t" }, 23 | { "ushort", "uint16_t" }, 24 | { "byte", "uint8_t" }, 25 | { "sbyte", "int8_t" }, 26 | 27 | { "float", "float" }, 28 | { "double", "double" }, 29 | 30 | { "char", "char" }, 31 | { "string", "string_t" }, 32 | 33 | { "System.Action", "action_t" }, 34 | { "object", "object_t" }, 35 | 36 | { "UInt8", "uint8_t" }, 37 | { "UInt16", "uint16_t" }, 38 | { "UInt32", "uint32_t" }, 39 | { "UInt64", "uint64_t" }, 40 | 41 | { "IntPtr", "intptr_t" }, 42 | { "UIntPtr", "uintptr_t" }, 43 | 44 | { "Char", "char" }, 45 | { "Int8", "int8_t" }, 46 | { "Int16", "int16_t" }, 47 | { "Int32", "int32_t" }, 48 | { "Int64", "int64_t" }, 49 | { "Boolean", "bool_t" }, 50 | { "Byte", "uint8_t" } 51 | }; 52 | 53 | /// 54 | /// Checks if a given C# type is a generic type 55 | /// 56 | /// The C# type 57 | /// If the type is a generic type 58 | public bool IsGeneric(ITypeSymbol type) 59 | { 60 | return m_convert.ContainsKey(type.ToString().Trim()); 61 | } 62 | 63 | /// 64 | /// Checks if a given C# type is a generic type 65 | /// 66 | /// The C# type name 67 | /// If the type is a generic type 68 | public bool IsGeneric(string type) 69 | { 70 | return m_convert.ContainsKey(type); 71 | } 72 | 73 | /// 74 | /// Converts the given C# type to a C type 75 | /// 76 | /// The C# type 77 | /// The C type 78 | public string Convert(ITypeSymbol type) 79 | { 80 | return m_convert[type.ToString().Trim()]; 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /LibCS2C/Context/MethodTable.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.CodeAnalysis; 2 | using Microsoft.CodeAnalysis.CSharp.Syntax; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Collections.Immutable; 6 | using System.Linq; 7 | using System.Text; 8 | 9 | namespace LibCS2C.Context 10 | { 11 | public class MethodTable 12 | { 13 | private Dictionary> m_methods = new Dictionary>(); 14 | private Dictionary> m_methodsPerClass = new Dictionary>(); 15 | 16 | private WalkerContext m_context; 17 | 18 | /// 19 | /// Initializes the method table 20 | /// 21 | /// The current context 22 | public MethodTable(WalkerContext context) 23 | { 24 | m_context = context; 25 | } 26 | 27 | /// 28 | /// Clears the table 29 | /// 30 | public void Clear() 31 | { 32 | m_methods.Clear(); 33 | } 34 | 35 | /// 36 | /// Adds current class 37 | /// 38 | public void AddCurrentClass() 39 | { 40 | string currentClassName = m_context.TypeConvert.CurrentClassNameFormatted; 41 | if (!m_methodsPerClass.ContainsKey(currentClassName)) 42 | m_methodsPerClass.Add(currentClassName, new List()); 43 | } 44 | 45 | /// 46 | /// Adds a new method to the table 47 | /// 48 | /// The method declaration 49 | public void Add(MethodDeclarationSyntax method) 50 | { 51 | string str = GetMethodLookupName(method); 52 | string currentClassName = m_context.TypeConvert.CurrentClassNameFormatted; 53 | string className = currentClassName; 54 | 55 | TypeDeclarationSyntax parent = method.Parent as TypeDeclarationSyntax; 56 | bool found = false; 57 | if (parent.BaseList != null) 58 | { 59 | IEnumerable children = parent.BaseList.ChildNodes(); 60 | 61 | foreach (SimpleBaseTypeSyntax child in children) 62 | { 63 | IdentifierNameSyntax identifier = child.ChildNodes().First() as IdentifierNameSyntax; 64 | 65 | ITypeSymbol typeSymbol = m_context.Model.GetTypeInfo(identifier).Type; 66 | 67 | ImmutableArray members = typeSymbol.GetMembers(); 68 | foreach (ISymbol member in members) 69 | { 70 | if (member.Name == method.Identifier.ToString()) 71 | { 72 | className = string.Format("{0}_{1}", m_context.ConvertNameSpace(typeSymbol.ContainingNamespace), typeSymbol.Name); 73 | found = true; 74 | break; 75 | } 76 | } 77 | } 78 | } 79 | 80 | if (!found) 81 | return; 82 | 83 | if (!m_methods.ContainsKey(className)) 84 | m_methods.Add(className, new List()); 85 | 86 | if (!m_methodsPerClass.ContainsKey(currentClassName)) 87 | m_methodsPerClass.Add(currentClassName, new List()); 88 | 89 | m_methods[className].Add(str); 90 | m_methodsPerClass[currentClassName].Add(str); 91 | } 92 | 93 | /// 94 | /// Gets the ID of a method 95 | /// 96 | /// The class name 97 | /// The method declaration 98 | /// Its ID 99 | public int GetID(string className, MethodDeclarationSyntax method) 100 | { 101 | // Terrible hack 102 | string str = GetMethodLookupName(method); 103 | if (!m_methods.ContainsKey(className)) 104 | { 105 | m_methods.Add(className, new List()); 106 | m_methods[className].Add(str); 107 | } 108 | if (m_methods[className].IndexOf(str) == -1) 109 | m_methods[className].Add(str); 110 | return m_methods[className].IndexOf(str); 111 | } 112 | 113 | /// 114 | /// Gets the lookup name of a method 115 | /// 116 | /// The method declaration 117 | /// Its lookup name 118 | private string GetMethodLookupName(MethodDeclarationSyntax method) 119 | { 120 | TypeDeclarationSyntax parent = method.Parent as TypeDeclarationSyntax; 121 | 122 | SyntaxTree owningTree = method.Parent.SyntaxTree; 123 | SemanticModel model = m_context.Model.Compilation.GetSemanticModel(owningTree); 124 | IMethodSymbol symbol = (IMethodSymbol)model.GetDeclaredSymbol(method); 125 | 126 | string suffix = string.Format("{0}_{1}", m_context.ConvertNameSpace(symbol.ContainingNamespace), parent.Identifier.ToString()); 127 | string str = m_context.Generators.MethodDeclaration.CreateMethodPrototype(symbol, false, false); 128 | 129 | return str.Substring(suffix.Length); 130 | } 131 | 132 | /// 133 | /// Converts the method table to a prototype C array 134 | /// 135 | /// The code 136 | public string ToPrototypeArrayCode() 137 | { 138 | StringBuilder sb = new StringBuilder(); 139 | 140 | foreach (KeyValuePair> pair in m_methodsPerClass) 141 | { 142 | sb.AppendLine(string.Format("static void* methods_{0}[];", pair.Key)); 143 | } 144 | 145 | return sb.ToString(); 146 | } 147 | 148 | /// 149 | /// Converts the method table to a C array 150 | /// 151 | /// The code 152 | public string ToArrayCode() 153 | { 154 | StringBuilder sb = new StringBuilder(); 155 | 156 | foreach (KeyValuePair> pair in m_methodsPerClass) 157 | { 158 | sb.Append(string.Format("static void* methods_{0}[] = ", pair.Key)); 159 | sb.Append("{"); 160 | pair.Value.ForEach((string prototype) => 161 | { 162 | sb.Append(string.Format("{0}{1},", pair.Key, prototype)); 163 | }); 164 | sb.AppendLine("};"); 165 | } 166 | 167 | return sb.ToString(); 168 | } 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /LibCS2C/Context/TypeConversion.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.CodeAnalysis; 2 | using Microsoft.CodeAnalysis.CSharp; 3 | using Microsoft.CodeAnalysis.CSharp.Syntax; 4 | using System; 5 | using System.Collections.Generic; 6 | 7 | namespace LibCS2C.Context 8 | { 9 | public class TypeConversion 10 | { 11 | /// 12 | /// Formatted current class name 13 | /// 14 | public string CurrentClassNameFormatted { get { return ConvertClassName(m_context.CurrentClass.Identifier.ToString()); } } 15 | 16 | /// 17 | /// Gets the current class converted to the struct name 18 | /// 19 | public string CurrentClassStructName { get { return string.Format("struct class_{0}", CurrentClassNameFormatted); } } 20 | 21 | /// 22 | /// Gets the current namespace name formatted 23 | /// 24 | public string CurrentNamespaceFormatted { get { return m_context.CurrentNamespace.Name.ToString().Replace(".", "_"); } } 25 | 26 | // The context 27 | private WalkerContext m_context; 28 | 29 | /// 30 | /// Creates the type conversion helper 31 | /// 32 | /// The context 33 | public TypeConversion(WalkerContext context) 34 | { 35 | m_context = context; 36 | } 37 | 38 | /// 39 | /// Convert class name in the current namespace to a formatted name 40 | /// 41 | /// The class name 42 | /// The formatted name 43 | public string ConvertClassName(string identifier) 44 | { 45 | return m_context.TypeConvert.CurrentNamespaceFormatted + "_" + identifier; 46 | } 47 | 48 | /// 49 | /// Converts the C# type to a C type name 50 | /// 51 | /// The C# type 52 | /// The C type name 53 | public string ConvertTypeName(ITypeSymbol type) 54 | { 55 | string typeNameConverted; 56 | 57 | bool nameContainsType = (type.ContainingType == null); 58 | string containingType = nameContainsType ? type.ToString().Replace('.', '_') : type.ContainingType.ToString().Replace('.', '_'); 59 | string nameSpace = (type.ContainingNamespace == null) ? "" : m_context.ConvertNameSpace(type.ContainingNamespace); 60 | 61 | if (type.TypeKind == TypeKind.Class) 62 | { 63 | if (nameContainsType) 64 | typeNameConverted = string.Format("struct class_{0}*", containingType); 65 | else 66 | typeNameConverted = string.Format("struct class_{0}_{1}*", containingType, type.Name); 67 | } 68 | else if (type.TypeKind == TypeKind.Enum) 69 | { 70 | typeNameConverted = "int32_t"; 71 | } 72 | else if (type.TypeKind == TypeKind.Struct) 73 | { 74 | if (nameContainsType) 75 | typeNameConverted = string.Format("struct struct_{0}", containingType); 76 | else 77 | typeNameConverted = string.Format("struct struct_{0}_{1}", containingType, type.Name); 78 | } 79 | else if (type.TypeKind == TypeKind.Pointer) 80 | { 81 | IPointerTypeSymbol pointer = (IPointerTypeSymbol)type; 82 | typeNameConverted = m_context.ConvertTypeName(pointer.PointedAtType) + "*"; 83 | } 84 | else if (type.TypeKind == TypeKind.Array) 85 | { 86 | IArrayTypeSymbol array = (IArrayTypeSymbol)type; 87 | typeNameConverted = m_context.ConvertTypeName(array.ElementType) + new string('*', array.Rank); 88 | } 89 | else if (type.TypeKind == TypeKind.Delegate) 90 | { 91 | typeNameConverted = string.Format("delegate_{0}", type.ToString().Replace('.', '_')); 92 | } 93 | else if (type.TypeKind == TypeKind.Class) 94 | { 95 | typeNameConverted = string.Format("struct class_{0}_{1}*", nameSpace, type.ToString()); 96 | } 97 | else if (type.TypeKind == TypeKind.Enum) 98 | { 99 | typeNameConverted = "int32_t"; 100 | } 101 | else if (type.TypeKind == TypeKind.Interface) 102 | { 103 | typeNameConverted = "struct base_class*"; 104 | } 105 | else 106 | { 107 | throw new NotImplementedException("Could not convert type name: " + type.TypeKind + " is unimplemented"); 108 | } 109 | 110 | return typeNameConverted; 111 | } 112 | 113 | /// 114 | /// Converts a variable name from C# to C 115 | /// 116 | /// The node 117 | /// The converted variable name 118 | public string ConvertVariableName(SyntaxNode node) 119 | { 120 | string typeNameConverted; 121 | ISymbol symbol = m_context.Model.GetSymbolInfo(node).Symbol; 122 | 123 | // Property 124 | if (symbol.Kind == SymbolKind.Property) 125 | { 126 | if (symbol.IsStatic) 127 | { 128 | typeNameConverted = string.Format("{0}_{1}_getter()", symbol.ContainingType.ToString().Replace(".", "_"), symbol.Name); 129 | } 130 | else 131 | { 132 | typeNameConverted = string.Format("{0}_{1}_getter", symbol.ContainingType.ToString().Replace(".", "_"), symbol.Name); 133 | string currentClass = m_context.CurrentNamespace.Name + "." + m_context.CurrentClass.Identifier; 134 | if (currentClass == symbol.ContainingType.ToString()) 135 | { 136 | typeNameConverted += "(obj)"; 137 | } 138 | } 139 | } 140 | // Method 141 | else if (symbol.Kind == SymbolKind.Method) 142 | { 143 | typeNameConverted = m_context.Generators.MethodDeclaration.CreateMethodPrototype((IMethodSymbol)symbol, false, false); 144 | } 145 | // Static field 146 | else if (symbol.IsStatic) 147 | { 148 | FieldDeclarationSyntax fieldDeclaration = symbol.DeclaringSyntaxReferences[0].GetSyntax().Parent.Parent as FieldDeclarationSyntax; 149 | IEnumerable children = fieldDeclaration.ChildTokens(); 150 | 151 | bool isConst = false; 152 | foreach (SyntaxToken token in children) 153 | { 154 | if (token.Kind() == SyntaxKind.ConstKeyword) 155 | { 156 | isConst = true; 157 | break; 158 | } 159 | } 160 | 161 | if (isConst) 162 | typeNameConverted = string.Format("const_{0}_{1}", symbol.ContainingType.ToString().Replace(".", "_"), symbol.Name); 163 | else 164 | typeNameConverted = string.Format("classStatics_{0}.{1}", symbol.ContainingType.ToString().Replace(".", "_"), symbol.Name); 165 | } 166 | // Argument or local variable 167 | else if (symbol.ContainingSymbol.Kind == SymbolKind.Method) 168 | { 169 | typeNameConverted = symbol.Name; 170 | } 171 | // Field 172 | else 173 | { 174 | typeNameConverted = string.Format("field_{0}", symbol.Name); 175 | } 176 | 177 | return typeNameConverted; 178 | } 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /LibCS2C/Context/WalkerContext.cs: -------------------------------------------------------------------------------- 1 | using LibCS2C.Generators; 2 | using LibCS2C.Util; 3 | using Microsoft.CodeAnalysis; 4 | using Microsoft.CodeAnalysis.CSharp.Syntax; 5 | using System; 6 | using System.Collections.Generic; 7 | 8 | namespace LibCS2C.Context 9 | { 10 | public class WalkerContext 11 | { 12 | /// 13 | /// Generic type conversion helper 14 | /// 15 | public GenericTypeConversion GenericTypeConvert { get; private set; } = new GenericTypeConversion(); 16 | 17 | /// 18 | /// Type conversion helper 19 | /// 20 | public TypeConversion TypeConvert { get; private set; } 21 | 22 | /// 23 | /// Method table 24 | /// 25 | public MethodTable MethodTable { get; private set; } 26 | 27 | /// 28 | /// If a class is ever extended by another type 29 | /// 30 | public Dictionary TypeIsExtending { get; private set; } = new Dictionary(); 31 | 32 | /// 33 | /// .cctor list 34 | /// 35 | public List CctorList { get; private set; } = new List(); 36 | 37 | /// 38 | /// The current class 39 | /// 40 | public ClassDeclarationSyntax CurrentClass { get; set; } 41 | 42 | /// 43 | /// The current namespace 44 | /// 45 | public NamespaceDeclarationSyntax CurrentNamespace { get; set; } 46 | 47 | /// 48 | /// Gets the semantic Model 49 | /// 50 | public SemanticModel Model { get; set; } 51 | 52 | /// 53 | /// A list with all the generators 54 | /// 55 | public AllGenerators Generators { get; private set; } 56 | 57 | /// 58 | /// The writer 59 | /// 60 | public Writer Writer { get; private set; } 61 | 62 | /// 63 | /// Contextwalker 64 | /// 65 | /// The formatted string builder 66 | public WalkerContext() 67 | { 68 | Generators = new AllGenerators(this); 69 | TypeConvert = new TypeConversion(this); 70 | MethodTable = new MethodTable(this); 71 | Writer = new Writer(); 72 | } 73 | 74 | /// 75 | /// Converts the C# type to a C type name 76 | /// 77 | /// The C# type 78 | /// The C type name 79 | public string ConvertTypeName(ITypeSymbol type) 80 | { 81 | if (GenericTypeConvert.IsGeneric(type)) 82 | { 83 | return GenericTypeConvert.Convert(type); 84 | } 85 | else 86 | { 87 | return TypeConvert.ConvertTypeName(type); 88 | } 89 | } 90 | 91 | /// 92 | /// Converts the C# type to a C type name 93 | /// 94 | /// The C# type 95 | /// The C type name 96 | public string ConvertTypeName(TypeSyntax type) 97 | { 98 | ITypeSymbol symbol = Model.GetTypeInfo(type).Type; 99 | return ConvertTypeName(symbol); 100 | } 101 | 102 | /// 103 | /// Converts a namespace to a C namespace name 104 | /// 105 | /// The namespace 106 | /// The C name 107 | public string ConvertNameSpace(INamespaceSymbol nameSpace) 108 | { 109 | return nameSpace.ToString().Replace('.', '_'); 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /LibCS2C/Context/Writer.cs: -------------------------------------------------------------------------------- 1 | using LibCS2C.Util; 2 | 3 | namespace LibCS2C.Context 4 | { 5 | public class Writer 6 | { 7 | /// 8 | /// Gets the output writer 9 | /// 10 | public FormattedStringBuilder CurrentWriter { get; private set; } 11 | 12 | /// 13 | /// If a code should be outputted after the current code 14 | /// 15 | public bool ShouldOutputPost { get; set; } = false; 16 | 17 | // String builders 18 | public FormattedStringBuilder SbEnums { get; private set; } = new FormattedStringBuilder(); 19 | public FormattedStringBuilder SbStructs { get; private set; } = new FormattedStringBuilder(); 20 | public FormattedStringBuilder SbStructPrototypes { get; private set; } = new FormattedStringBuilder(); 21 | public FormattedStringBuilder SbClassStructs { get; private set; } = new FormattedStringBuilder(); 22 | public FormattedStringBuilder SbDelegates { get; private set; } = new FormattedStringBuilder(); 23 | public FormattedStringBuilder SbMethodPrototypes { get; private set; } = new FormattedStringBuilder(); 24 | public FormattedStringBuilder SbMethodDeclarations { get; private set; } = new FormattedStringBuilder(); 25 | private FormattedStringBuilder m_sbTempBuffer = new FormattedStringBuilder(); 26 | private FormattedStringBuilder m_sbPostBuffer = new FormattedStringBuilder(); 27 | private FormattedStringBuilder[] m_stringBuilders; 28 | 29 | // Current writing destination 30 | private WriterDestination m_currentDestination; 31 | 32 | /// 33 | /// Current destionation of the writer, this is because a destination depends on the structure of the code 34 | /// Therefor, we cannot assume one generator is one writer 35 | /// 36 | public WriterDestination CurrentDestination 37 | { 38 | get 39 | { 40 | return m_currentDestination; 41 | } 42 | 43 | set 44 | { 45 | m_currentDestination = value; 46 | CurrentWriter = m_stringBuilders[(int)value]; 47 | } 48 | } 49 | 50 | /// 51 | /// Initializes the writer 52 | /// 53 | public Writer() 54 | { 55 | m_stringBuilders = new FormattedStringBuilder[] { SbEnums, SbStructPrototypes, SbStructs, SbClassStructs, SbDelegates, SbMethodPrototypes, SbMethodDeclarations, m_sbTempBuffer, m_sbPostBuffer }; 56 | } 57 | 58 | /// 59 | /// Adds a tab 60 | /// 61 | public void Indent() 62 | { 63 | CurrentWriter.Indent(); 64 | } 65 | 66 | /// 67 | /// Removes a tab 68 | /// 69 | public void UnIndent() 70 | { 71 | CurrentWriter.UnIndent(); 72 | } 73 | 74 | /// 75 | /// Appends the indent tabs 76 | /// 77 | public void AppendIndent() 78 | { 79 | CurrentWriter.AppendIndent(); 80 | } 81 | 82 | /// 83 | /// Appends text 84 | /// 85 | /// The text 86 | public void Append(string text) 87 | { 88 | CurrentWriter.Append(text); 89 | } 90 | 91 | /// 92 | /// Appends text and a new line 93 | /// 94 | /// The text 95 | public void AppendLine(string text) 96 | { 97 | CurrentWriter.AppendLine(text); 98 | } 99 | 100 | /// 101 | /// Flushes the temporary buffer 102 | /// 103 | /// The buffer contents 104 | public string FlushTempBuffer() 105 | { 106 | string ret = m_sbTempBuffer.ToString(); 107 | m_sbTempBuffer.Clear(); 108 | return ret; 109 | } 110 | 111 | /// 112 | /// Checks if the post buffer is empty 113 | /// 114 | /// If it's empty 115 | public bool IsPostBufferEmpty() 116 | { 117 | return m_sbPostBuffer.IsEmpty(); 118 | } 119 | 120 | /// 121 | /// Flushes the post buffer 122 | /// 123 | /// The buffer contents 124 | public string FlushPostBuffer() 125 | { 126 | string ret = m_sbPostBuffer.ToString(); 127 | m_sbPostBuffer.Clear(); 128 | return ret; 129 | } 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /LibCS2C/Context/WriterDestination.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace LibCS2C.Context 8 | { 9 | public enum WriterDestination 10 | { 11 | Defines, 12 | StructPrototypes, 13 | Structs, 14 | ClassStructs, 15 | Delegates, 16 | MethodPrototypes, 17 | MethodDeclarations, 18 | TempBuffer, 19 | PostBuffer 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /LibCS2C/Generators/AddressOfExpressionGenerator.cs: -------------------------------------------------------------------------------- 1 | using LibCS2C.Context; 2 | using Microsoft.CodeAnalysis.CSharp.Syntax; 3 | 4 | namespace LibCS2C.Generators 5 | { 6 | public class AddressOfExpressionGenerator : GeneratorBase 7 | { 8 | /// 9 | /// Address of expression generator 10 | /// 11 | /// The walker context 12 | public AddressOfExpressionGenerator(WalkerContext context) 13 | { 14 | m_context = context; 15 | } 16 | 17 | /// 18 | /// Generates an address of expression 19 | /// 20 | /// The address of expression 21 | public override void Generate(PrefixUnaryExpressionSyntax node) 22 | { 23 | m_context.Writer.Append("&"); 24 | m_context.Generators.Expression.Generate(node.Operand); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /LibCS2C/Generators/AllGenerators.cs: -------------------------------------------------------------------------------- 1 | using LibCS2C.Context; 2 | 3 | namespace LibCS2C.Generators 4 | { 5 | public class AllGenerators 6 | { 7 | public AssignmentGenerator AddAssignment { get; private set; } 8 | public AddressOfExpressionGenerator AddressOfExpression { get; private set; } 9 | public ArgumentListGenerator ArgumentList { get; private set; } 10 | public ArrayCreationExpressionGenerator ArrayCreationExpression { get; private set; } 11 | public ArrayInitializerGenerator ArrayInitializerExpression { get; private set; } 12 | public AssignmentGenerator BinaryAndAssignment { get; private set; } 13 | public AssignmentGenerator BinaryOrAssignment { get; private set; } 14 | public BlockGenerator Block { get; private set; } 15 | public CastExpressionGenerator CastExpression { get; private set; } 16 | public ConditionalAccessExpressionGenerator ConditionalAccessExpression { get; private set; } 17 | public ClassCodeGenerator ClassCode { get; private set; } 18 | public DelegateDeclarationGenerator DelegateDeclaration { get; private set; } 19 | public DoStatementGenerator DoStatement { get; private set; } 20 | public AssignmentGenerator DivideAssignment { get; private set; } 21 | public ElementAccessGenerator ElementAccess { get; private set; } 22 | public EnumGenerator Enum { get; private set; } 23 | public AssignmentGenerator ExclusiveOrAssignment { get; private set; } 24 | public ExpressionGenerator Expression { get; private set; } 25 | public ExpressionStatementGenerator ExpressionStatement { get; private set; } 26 | public FixedStatementGenerator FixedStatement { get; private set; } 27 | public ForStatementGenerator ForStatement { get; private set; } 28 | public GotoStatementGenerator GotoStatement { get; private set; } 29 | public IfStatementGenerator IfStatement { get; private set; } 30 | public InvocationGenerator Invocation { get; private set; } 31 | public InterfaceGenerator Interface { get; private set; } 32 | public IdentifierNameGenerator IdentifierName { get; private set; } 33 | public LabeledStatementGenerator LabeledStatement { get; private set; } 34 | public AssignmentGenerator LeftShiftAssignment { get; private set; } 35 | public LocalDeclarationGenerator LocalDeclaration { get; private set; } 36 | public MethodGenerator MethodDeclaration { get; private set; } 37 | public AssignmentGenerator ModuloAssignment { get; private set; } 38 | public AssignmentGenerator MultiplyAssignment { get; private set; } 39 | public ObjectCreationExpressionGenerator ObjectCreationExpression { get; private set; } 40 | public PrePostExpressionGenerator PreIncrementExpression { get; private set; } 41 | public PrePostExpressionGenerator PreDecrementExpression { get; private set; } 42 | public PrePostExpressionGenerator PostIncrementExpression { get; private set; } 43 | public PrePostExpressionGenerator PostDecrementExpression { get; private set; } 44 | public PointerMemberAccessGenerator PointerMemberAccessExpression { get; private set; } 45 | public PropertyGenerator Property { get; private set; } 46 | public ReturnStatementGenerator ReturnStatement { get; private set; } 47 | public AssignmentGenerator RightShiftAssignment { get; private set; } 48 | public SimpleAssignmentGenerator SimpleAssignment { get; private set; } 49 | public SimpleMemberAccessGenerator SimpleMemberAccess { get; private set; } 50 | public SizeofExpressionGenerator SizeOfExpression { get; private set; } 51 | public StructGenerator Struct { get; private set; } 52 | public AssignmentGenerator SubstractAssignment { get; private set; } 53 | public SwitchStatementGenerator SwitchStatement { get; private set; } 54 | public checkedStatementGenerator checkedStatement { get; private set; } 55 | public VariableGenerator Variable { get; private set; } 56 | public WhileStatementGenerator WhileStatement { get; private set; } 57 | 58 | /// 59 | /// A list with all the generators 60 | /// 61 | /// The context 62 | public AllGenerators(WalkerContext context) 63 | { 64 | AddAssignment = new AssignmentGenerator(context, AssignmentType.Add); 65 | AddressOfExpression = new AddressOfExpressionGenerator(context); 66 | ArgumentList = new ArgumentListGenerator(context); 67 | ArrayCreationExpression = new ArrayCreationExpressionGenerator(context); 68 | ArrayInitializerExpression = new ArrayInitializerGenerator(context); 69 | BinaryAndAssignment = new AssignmentGenerator(context, AssignmentType.BinaryAnd); 70 | BinaryOrAssignment = new AssignmentGenerator(context, AssignmentType.BinaryOr); 71 | Block = new BlockGenerator(context); 72 | CastExpression = new CastExpressionGenerator(context); 73 | ConditionalAccessExpression = new ConditionalAccessExpressionGenerator(context); 74 | ClassCode = new ClassCodeGenerator(context); 75 | DelegateDeclaration = new DelegateDeclarationGenerator(context); 76 | DoStatement = new DoStatementGenerator(context); 77 | DivideAssignment = new AssignmentGenerator(context, AssignmentType.Divide); 78 | ElementAccess = new ElementAccessGenerator(context); 79 | Enum = new EnumGenerator(context); 80 | ExclusiveOrAssignment = new AssignmentGenerator(context, AssignmentType.ExclusiveOr); 81 | Expression = new ExpressionGenerator(context); 82 | ExpressionStatement = new ExpressionStatementGenerator(context); 83 | FixedStatement = new FixedStatementGenerator(context); 84 | ForStatement = new ForStatementGenerator(context); 85 | GotoStatement = new GotoStatementGenerator(context); 86 | IfStatement = new IfStatementGenerator(context); 87 | Invocation = new InvocationGenerator(context); 88 | Interface = new InterfaceGenerator(context); 89 | IdentifierName = new IdentifierNameGenerator(context); 90 | LabeledStatement = new LabeledStatementGenerator(context); 91 | LeftShiftAssignment = new AssignmentGenerator(context, AssignmentType.LeftShift); 92 | LocalDeclaration = new LocalDeclarationGenerator(context); 93 | MethodDeclaration = new MethodGenerator(context); 94 | ModuloAssignment = new AssignmentGenerator(context, AssignmentType.Modulo); 95 | MultiplyAssignment = new AssignmentGenerator(context, AssignmentType.Multiply); 96 | ObjectCreationExpression = new ObjectCreationExpressionGenerator(context); 97 | PreIncrementExpression = new PrePostExpressionGenerator(context, ExpressionType.PreIncrement); 98 | PreDecrementExpression = new PrePostExpressionGenerator(context, ExpressionType.PreDecrement); 99 | PostIncrementExpression = new PrePostExpressionGenerator(context, ExpressionType.PostIncrement); 100 | PostDecrementExpression = new PrePostExpressionGenerator(context, ExpressionType.PostDecrement); 101 | PointerMemberAccessExpression = new PointerMemberAccessGenerator(context); 102 | Property = new PropertyGenerator(context); 103 | ReturnStatement = new ReturnStatementGenerator(context); 104 | RightShiftAssignment = new AssignmentGenerator(context, AssignmentType.RightShift); 105 | SimpleAssignment = new SimpleAssignmentGenerator(context); 106 | SimpleMemberAccess = new SimpleMemberAccessGenerator(context); 107 | SizeOfExpression = new SizeofExpressionGenerator(context); 108 | Struct = new StructGenerator(context); 109 | SubstractAssignment = new AssignmentGenerator(context, AssignmentType.Substract); 110 | SwitchStatement = new SwitchStatementGenerator(context); 111 | checkedStatement = new checkedStatementGenerator(context); 112 | Variable = new VariableGenerator(context); 113 | WhileStatement = new WhileStatementGenerator(context); 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /LibCS2C/Generators/ArgumentListGenerator.cs: -------------------------------------------------------------------------------- 1 | using LibCS2C.Context; 2 | using Microsoft.CodeAnalysis; 3 | using Microsoft.CodeAnalysis.CSharp; 4 | using Microsoft.CodeAnalysis.CSharp.Syntax; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | 9 | namespace LibCS2C.Generators 10 | { 11 | public class ArgumentListGenerator : GeneratorBase 12 | { 13 | /// 14 | /// Argument list generator 15 | /// 16 | /// The walker context 17 | public ArgumentListGenerator(WalkerContext context) 18 | { 19 | m_context = context; 20 | } 21 | 22 | /// 23 | /// Generates an argument 24 | /// 25 | /// The argument 26 | public void GenerateArgument(ArgumentSyntax arg) 27 | { 28 | IEnumerable children = arg.ChildNodes(); 29 | foreach (ExpressionSyntax child in children) 30 | { 31 | ITypeSymbol type = m_context.Model.GetTypeInfo(child).Type; 32 | 33 | if (type != null && !m_context.GenericTypeConvert.IsGeneric(type) && type.TypeKind == TypeKind.Class) 34 | m_context.Writer.Append("(void*)"); 35 | 36 | m_context.Generators.Expression.Generate(child); 37 | } 38 | } 39 | 40 | /// 41 | /// Generates the argument list code 42 | /// 43 | /// The argument list 44 | public override void Generate(ArgumentListSyntax node) 45 | { 46 | IEnumerable argNodes = node.ChildNodes(); 47 | foreach (ArgumentSyntax argument in argNodes) 48 | { 49 | GenerateArgument(argument); 50 | 51 | // A comma if it's not the last argument 52 | if (argument != argNodes.Last()) 53 | m_context.Writer.Append(", "); 54 | } 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /LibCS2C/Generators/ArrayCreationExpressionGenerator.cs: -------------------------------------------------------------------------------- 1 | using LibCS2C.Context; 2 | using Microsoft.CodeAnalysis; 3 | using Microsoft.CodeAnalysis.CSharp.Syntax; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | 7 | namespace LibCS2C.Generators 8 | { 9 | public class ArrayCreationExpressionGenerator : GeneratorBase 10 | { 11 | /// 12 | /// Sizeof statement generator 13 | /// 14 | /// The walker context 15 | public ArrayCreationExpressionGenerator(WalkerContext context) 16 | { 17 | m_context = context; 18 | } 19 | 20 | /// 21 | /// Generates an array creation expression 22 | /// 23 | /// The array creation expression 24 | public override void Generate(ArrayCreationExpressionSyntax node) 25 | { 26 | IEnumerable children = node.Type.ChildNodes(); 27 | SyntaxNode second = children.ElementAt(1); 28 | 29 | ArrayRankSpecifierSyntax rank = second as ArrayRankSpecifierSyntax; 30 | ExpressionSyntax sizeExpression = rank.Sizes.First(); 31 | 32 | // Malloc returns a pointer to the type 33 | // So that means this type has a pointer too much 34 | string type = m_context.ConvertTypeName(node.Type); 35 | type = type.Substring(0, type.Length - 1); 36 | 37 | /*m_context.Writer.Append(string.Format("malloc(sizeof({0}) * (", type)); 38 | m_context.Generators.Expression.Generate(sizeExpression); 39 | m_context.Writer.Append("))");*/ 40 | 41 | m_context.Writer.Append("calloc(("); 42 | m_context.Generators.Expression.Generate(sizeExpression); 43 | m_context.Writer.Append(string.Format("), sizeof({0}))", type)); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /LibCS2C/Generators/ArrayInitializerGenerator.cs: -------------------------------------------------------------------------------- 1 | using LibCS2C.Context; 2 | using Microsoft.CodeAnalysis; 3 | using Microsoft.CodeAnalysis.CSharp.Syntax; 4 | 5 | namespace LibCS2C.Generators 6 | { 7 | public class ArrayInitializerGenerator : GeneratorBase 8 | { 9 | /// 10 | /// Array initializer expression generator 11 | /// 12 | /// The walker context 13 | public ArrayInitializerGenerator(WalkerContext context) 14 | { 15 | m_context = context; 16 | } 17 | 18 | /// 19 | /// Generates an array intializer 20 | /// 21 | /// The expression 22 | public override void Generate(InitializerExpressionSyntax node) 23 | { 24 | SeparatedSyntaxList children = node.Expressions; 25 | 26 | m_context.Writer.Append("{"); 27 | foreach (ExpressionSyntax child in children) 28 | { 29 | m_context.Generators.Expression.Generate(child); 30 | 31 | if (child != children.Last()) 32 | m_context.Writer.Append(", "); 33 | } 34 | m_context.Writer.Append("}"); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /LibCS2C/Generators/AssignmentGenerator.cs: -------------------------------------------------------------------------------- 1 | using LibCS2C.Context; 2 | using Microsoft.CodeAnalysis; 3 | using Microsoft.CodeAnalysis.CSharp; 4 | using Microsoft.CodeAnalysis.CSharp.Syntax; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | 11 | namespace LibCS2C.Generators 12 | { 13 | public enum AssignmentType 14 | { 15 | LeftShift, 16 | RightShift, 17 | BinaryOr, 18 | ExclusiveOr, 19 | BinaryAnd, 20 | Add, 21 | Substract, 22 | Multiply, 23 | Divide, 24 | Modulo 25 | } 26 | 27 | public class AssignmentGenerator : GeneratorBase 28 | { 29 | private AssignmentType m_assignmentType; 30 | 31 | /// 32 | /// Assignment generator 33 | /// 34 | /// The walker context 35 | /// Assignment type 36 | public AssignmentGenerator(WalkerContext context, AssignmentType assignmentType) 37 | { 38 | m_context = context; 39 | m_assignmentType = assignmentType; 40 | } 41 | 42 | /// 43 | /// Generates the assignment 44 | /// 45 | /// The assignment 46 | public override void Generate(AssignmentExpressionSyntax node) 47 | { 48 | ISymbol symbol = m_context.Model.GetSymbolInfo(node.Left).Symbol; 49 | 50 | string assignmentSymbol = ""; 51 | switch (m_assignmentType) 52 | { 53 | case AssignmentType.BinaryAnd: 54 | assignmentSymbol = "&"; 55 | break; 56 | 57 | case AssignmentType.BinaryOr: 58 | assignmentSymbol = "|"; 59 | break; 60 | 61 | case AssignmentType.LeftShift: 62 | assignmentSymbol = "<<"; 63 | break; 64 | 65 | case AssignmentType.RightShift: 66 | assignmentSymbol = ">>"; 67 | break; 68 | 69 | case AssignmentType.ExclusiveOr: 70 | assignmentSymbol = "^"; 71 | break; 72 | 73 | case AssignmentType.Add: 74 | assignmentSymbol = "+"; 75 | break; 76 | 77 | case AssignmentType.Substract: 78 | assignmentSymbol = "-"; 79 | break; 80 | 81 | case AssignmentType.Multiply: 82 | assignmentSymbol = "*"; 83 | break; 84 | 85 | case AssignmentType.Divide: 86 | assignmentSymbol = "/"; 87 | break; 88 | 89 | case AssignmentType.Modulo: 90 | assignmentSymbol = "%"; 91 | break; 92 | } 93 | 94 | // Property (getter/setter required) 95 | if (symbol != null && symbol.Kind == SymbolKind.Property) 96 | { 97 | // Check for the object name 98 | string objectName = "obj"; 99 | IEnumerable children = node.Left.ChildNodes(); 100 | if (children.Count() > 1) 101 | { 102 | objectName = m_context.TypeConvert.ConvertVariableName(children.First()); 103 | } 104 | 105 | if (symbol.IsStatic) 106 | m_context.Writer.Append(string.Format("{0}_{1}_setter(", symbol.ContainingType.ToString().Replace(".", "_"), symbol.Name)); 107 | else 108 | m_context.Writer.Append(string.Format("{0}_{1}_setter({2}, ", symbol.ContainingType.ToString().Replace(".", "_"), symbol.Name, objectName)); 109 | 110 | m_context.Generators.Expression.Generate(node.Left); 111 | m_context.Writer.Append(string.Format(" {0} ", assignmentSymbol)); 112 | m_context.Generators.Expression.Generate(node.Right); 113 | m_context.Writer.Append(")"); 114 | } 115 | // Normal variable / field 116 | else 117 | { 118 | m_context.Generators.Expression.Generate(node.Left); 119 | m_context.Writer.Append(string.Format(" {0}= ", assignmentSymbol)); 120 | m_context.Generators.Expression.Generate(node.Right); 121 | } 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /LibCS2C/Generators/BlockGenerator.cs: -------------------------------------------------------------------------------- 1 | using LibCS2C.Context; 2 | using Microsoft.CodeAnalysis; 3 | using Microsoft.CodeAnalysis.CSharp; 4 | using Microsoft.CodeAnalysis.CSharp.Syntax; 5 | using System; 6 | using System.Collections.Generic; 7 | 8 | namespace LibCS2C.Generators 9 | { 10 | public class BlockGenerator : GeneratorBase 11 | { 12 | /// 13 | /// Block generator 14 | /// 15 | /// The walker context 16 | public BlockGenerator(WalkerContext context) 17 | { 18 | m_context = context; 19 | } 20 | 21 | /// 22 | /// Generate the child node 23 | /// 24 | /// The child node 25 | public void GenerateChild(SyntaxNode childNode) 26 | { 27 | bool semiColonNeeded = true; 28 | switch (childNode.Kind()) 29 | { 30 | case SyntaxKind.VariableDeclaration: 31 | m_context.Generators.Variable.Generate(childNode as VariableDeclarationSyntax); 32 | break; 33 | 34 | case SyntaxKind.ReturnStatement: 35 | m_context.Generators.ReturnStatement.Generate(childNode as ReturnStatementSyntax); 36 | break; 37 | 38 | case SyntaxKind.ExpressionStatement: 39 | m_context.Generators.ExpressionStatement.Generate(childNode as ExpressionStatementSyntax); 40 | break; 41 | 42 | case SyntaxKind.LocalDeclarationStatement: 43 | m_context.Generators.LocalDeclaration.Generate(childNode as LocalDeclarationStatementSyntax); 44 | break; 45 | 46 | case SyntaxKind.IfStatement: 47 | m_context.Generators.IfStatement.Generate(childNode as IfStatementSyntax); 48 | semiColonNeeded = false; 49 | break; 50 | 51 | case SyntaxKind.ForStatement: 52 | m_context.Generators.ForStatement.Generate(childNode as ForStatementSyntax); 53 | break; 54 | 55 | case SyntaxKind.WhileStatement: 56 | m_context.Generators.WhileStatement.Generate(childNode as WhileStatementSyntax); 57 | break; 58 | 59 | case SyntaxKind.FixedStatement: 60 | m_context.Generators.FixedStatement.Generate(childNode as FixedStatementSyntax); 61 | semiColonNeeded = false; 62 | break; 63 | 64 | case SyntaxKind.Block: 65 | m_context.Writer.AppendLine("{"); 66 | Generate(childNode as BlockSyntax); 67 | m_context.Writer.AppendLine("}"); 68 | semiColonNeeded = false; 69 | break; 70 | 71 | case SyntaxKind.DoStatement: 72 | m_context.Generators.DoStatement.Generate(childNode as DoStatementSyntax); 73 | break; 74 | 75 | case SyntaxKind.ContinueStatement: 76 | m_context.Writer.Append("continue"); 77 | break; 78 | 79 | case SyntaxKind.BreakStatement: 80 | m_context.Writer.Append("break"); 81 | break; 82 | 83 | case SyntaxKind.SwitchStatement: 84 | m_context.Generators.SwitchStatement.Generate(childNode as SwitchStatementSyntax); 85 | semiColonNeeded = false; 86 | break; 87 | 88 | case SyntaxKind.EmptyStatement: 89 | semiColonNeeded = false; 90 | break; 91 | 92 | case SyntaxKind.IdentifierName: 93 | m_context.Generators.IdentifierName.Generate(childNode as IdentifierNameSyntax); 94 | semiColonNeeded = false; 95 | break; 96 | 97 | case SyntaxKind.GotoStatement: 98 | m_context.Generators.GotoStatement.Generate(childNode as GotoStatementSyntax); 99 | semiColonNeeded = true; 100 | break; 101 | 102 | case SyntaxKind.LabeledStatement: 103 | m_context.Generators.LabeledStatement.Generate(childNode as LabeledStatementSyntax); 104 | break; 105 | 106 | case SyntaxKind.CheckedStatement: 107 | case SyntaxKind.UncheckedStatement: 108 | m_context.Generators.checkedStatement.Generate(childNode as CheckedStatementSyntax); 109 | break; 110 | 111 | default: 112 | throw new NotImplementedException("Unknown SyntaxKind in Block: " + childNode.Kind()); 113 | } 114 | 115 | // At the end of the line 116 | if (semiColonNeeded) 117 | m_context.Writer.AppendLine(";"); 118 | 119 | if (!m_context.Writer.IsPostBufferEmpty()) 120 | m_context.Writer.AppendLine(string.Format("{0};", m_context.Writer.FlushPostBuffer())); 121 | } 122 | 123 | /// 124 | /// Generates a block 125 | /// 126 | /// The block 127 | public override void Generate(BlockSyntax node) 128 | { 129 | m_context.Writer.Indent(); 130 | 131 | IEnumerable nodes = node.ChildNodes(); 132 | foreach (SyntaxNode childNode in nodes) 133 | { 134 | GenerateChild(childNode); 135 | } 136 | 137 | m_context.Writer.UnIndent(); 138 | } 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /LibCS2C/Generators/CastExpressionGenerator.cs: -------------------------------------------------------------------------------- 1 | using LibCS2C.Context; 2 | using Microsoft.CodeAnalysis.CSharp.Syntax; 3 | 4 | namespace LibCS2C.Generators 5 | { 6 | public class CastExpressionGenerator : GeneratorBase 7 | { 8 | /// 9 | /// Cast expression generator 10 | /// 11 | /// The walker context 12 | public CastExpressionGenerator(WalkerContext context) 13 | { 14 | m_context = context; 15 | } 16 | 17 | /// 18 | /// Generates a cast 19 | /// 20 | /// The cast 21 | public override void Generate(CastExpressionSyntax node) 22 | { 23 | m_context.Writer.Append(string.Format("({0})", m_context.ConvertTypeName(node.Type))); 24 | m_context.Generators.Expression.Generate(node.Expression); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /LibCS2C/Generators/ClassCctorGenerator.cs: -------------------------------------------------------------------------------- 1 | using LibCS2C.Context; 2 | using Microsoft.CodeAnalysis.CSharp.Syntax; 3 | using System.Collections.Generic; 4 | 5 | namespace LibCS2C.Generators 6 | { 7 | class ClassCctorGenerator : GeneratorBase 8 | { 9 | private ClassCodeData m_classCode; 10 | 11 | /// 12 | /// Class .cctor generator 13 | /// 14 | /// The walker context 15 | /// Class code 16 | public ClassCctorGenerator(WalkerContext context, ClassCodeData classCode) 17 | { 18 | m_context = context; 19 | m_classCode = classCode; 20 | } 21 | 22 | /// 23 | /// Checks if we need to generator Cctor code 24 | /// 25 | /// The value 26 | /// If we need Cctor code 27 | private bool needCctorCode(EqualsValueClauseSyntax value) 28 | { 29 | // If it's a literal expression, it is already in the struct initializer 30 | ExpressionSyntax expression = value.Value; 31 | return !m_context.Generators.Expression.IsLiteralExpression(expression.Kind()); 32 | } 33 | 34 | /// 35 | /// Generates the initializer 36 | /// 37 | /// The converted class name 38 | /// The name of the member 39 | /// The value 40 | private void GenerateInitializer(string className, string name, EqualsValueClauseSyntax value) 41 | { 42 | if (!needCctorCode(value)) 43 | return; 44 | 45 | m_context.Writer.Append(string.Format("\tclassStatics_{0}.{1} = ", className, name)); 46 | m_context.Generators.Expression.Generate(value.Value); 47 | m_context.Writer.AppendLine(";"); 48 | } 49 | 50 | /// 51 | /// Generate the .cctor method of a class 52 | /// 53 | /// The class declaration 54 | public override void Generate(ClassDeclarationSyntax node) 55 | { 56 | // Are there even things to initialize in the cctor? 57 | bool need = false; 58 | 59 | foreach (KeyValuePair pair in m_classCode.staticFields) 60 | { 61 | if (needCctorCode(pair.Value)) 62 | { 63 | need = true; 64 | break; 65 | } 66 | } 67 | 68 | foreach (KeyValuePair pair in m_classCode.propertyInitialValuesStatic) 69 | { 70 | if (needCctorCode(pair.Value)) 71 | { 72 | need = true; 73 | break; 74 | } 75 | } 76 | 77 | if (!need) 78 | return; 79 | 80 | string convertedClassName = m_context.TypeConvert.ConvertClassName(node.Identifier.ToString()); 81 | string methodName = string.Format("classCctor_{0}", convertedClassName); 82 | string methodPrototype = string.Format("void {0}(void)", methodName); 83 | 84 | // Add to .cctor list so we can call it on initialization 85 | m_context.CctorList.Add(methodName); 86 | 87 | // Prototype 88 | m_context.Writer.CurrentDestination = WriterDestination.MethodPrototypes; 89 | m_context.Writer.Append("extern " + methodPrototype); 90 | m_context.Writer.AppendLine(";"); 91 | 92 | // Declaration 93 | m_context.Writer.CurrentDestination = WriterDestination.MethodDeclarations; 94 | m_context.Writer.AppendLine("inline " + methodPrototype); 95 | m_context.Writer.AppendLine("{"); 96 | 97 | foreach (KeyValuePair pair in m_classCode.staticFields) 98 | { 99 | GenerateInitializer(convertedClassName, pair.Key, pair.Value); 100 | } 101 | 102 | foreach (KeyValuePair pair in m_classCode.propertyInitialValuesStatic) 103 | { 104 | GenerateInitializer(convertedClassName, "prop_" + pair.Key, pair.Value); 105 | } 106 | 107 | m_context.Writer.AppendLine("}"); 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /LibCS2C/Generators/ClassCode.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.CodeAnalysis.CSharp.Syntax; 2 | using System.Collections.Generic; 3 | 4 | namespace LibCS2C.Generators 5 | { 6 | public class ClassCodeData 7 | { 8 | public Dictionary staticFields { get; private set; } = new Dictionary(); 9 | public Dictionary nonStaticFields { get; private set; } = new Dictionary(); 10 | public Dictionary staticFieldTypes { get; private set; } = new Dictionary(); 11 | public Dictionary nonStaticFieldTypes { get; private set; } = new Dictionary(); 12 | public Dictionary propertyTypesNonStatic { get; private set; } = new Dictionary(); 13 | public Dictionary propertyInitialValuesNonStatic { get; private set; } = new Dictionary(); 14 | public Dictionary propertyTypesStatic { get; private set; } = new Dictionary(); 15 | public Dictionary propertyInitialValuesStatic { get; private set; } = new Dictionary(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /LibCS2C/Generators/ClassInitGenerator.cs: -------------------------------------------------------------------------------- 1 | using LibCS2C.Context; 2 | using Microsoft.CodeAnalysis.CSharp.Syntax; 3 | using System.Collections.Generic; 4 | 5 | namespace LibCS2C.Generators 6 | { 7 | class ClassInitGenerator : GeneratorBase 8 | { 9 | private ClassCodeData m_classCode; 10 | 11 | /// 12 | /// Class struct generator 13 | /// 14 | /// The walker context 15 | /// Class code 16 | public ClassInitGenerator(WalkerContext context, ClassCodeData classCode) 17 | { 18 | m_context = context; 19 | m_classCode = classCode; 20 | } 21 | 22 | /// 23 | /// Generates the class initialization method 24 | /// 25 | /// The class declaration 26 | public override void Generate(ClassDeclarationSyntax node) 27 | { 28 | string methodPrototype = string.Format("void* classInit_{0}_{1}(void)", m_context.TypeConvert.CurrentNamespaceFormatted, node.Identifier); 29 | 30 | // Method prototype 31 | m_context.Writer.CurrentDestination = WriterDestination.MethodPrototypes; 32 | m_context.Writer.Append(methodPrototype); 33 | m_context.Writer.AppendLine(";"); 34 | 35 | // Method declaration 36 | // Class initialization method: returns a pointer to this object 37 | m_context.Writer.CurrentDestination = WriterDestination.MethodDeclarations; 38 | m_context.Writer.AppendLine(methodPrototype); 39 | m_context.Writer.AppendLine("{"); 40 | m_context.Writer.AppendLine(string.Format("\t{0}* object = calloc(1, sizeof({0}));", m_context.TypeConvert.CurrentClassStructName)); 41 | m_context.Writer.AppendLine("\tif(!object) return NULL;"); 42 | 43 | // For indirect function calls 44 | m_context.Writer.AppendLine(string.Format("\tobject->lookup_table = methods_{0};", m_context.TypeConvert.CurrentClassNameFormatted)); 45 | 46 | // Loop through the fields and initialize them 47 | foreach (KeyValuePair pair in m_classCode.nonStaticFields) 48 | { 49 | m_context.Writer.Append(string.Format("\tobject->field_{0} = ", pair.Key)); 50 | ExpressionSyntax expression = pair.Value.Value; 51 | m_context.Generators.Expression.Generate(expression); 52 | m_context.Writer.AppendLine(";"); 53 | } 54 | 55 | // Loop through the properties and initialize them 56 | foreach (KeyValuePair pair in m_classCode.propertyInitialValuesNonStatic) 57 | { 58 | m_context.Writer.Append(string.Format("\tobject->prop_{0} = ", pair.Key)); 59 | ExpressionSyntax expression = pair.Value.Value; 60 | m_context.Generators.Expression.Generate(expression); 61 | m_context.Writer.AppendLine(";"); 62 | } 63 | 64 | m_context.Writer.AppendLine("\treturn object;"); 65 | m_context.Writer.AppendLine("}"); 66 | m_context.Writer.AppendLine(""); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /LibCS2C/Generators/ClassStaticStructGenerator.cs: -------------------------------------------------------------------------------- 1 | using LibCS2C.Context; 2 | using Microsoft.CodeAnalysis; 3 | using Microsoft.CodeAnalysis.CSharp; 4 | using Microsoft.CodeAnalysis.CSharp.Syntax; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | 9 | namespace LibCS2C.Generators 10 | { 11 | class ClassStaticStructGenerator : GeneratorBase 12 | { 13 | private ClassCodeData m_classCode; 14 | 15 | /// 16 | /// Class struct generator 17 | /// 18 | /// The walker context 19 | /// Class code 20 | public ClassStaticStructGenerator(WalkerContext context, ClassCodeData classCode) 21 | { 22 | m_context = context; 23 | m_classCode = classCode; 24 | } 25 | 26 | /// 27 | /// Generate the initializers 28 | /// 29 | /// Types 30 | /// Values 31 | private void GenerateInitializer(Dictionary types, Dictionary values) 32 | { 33 | // Loop through and initialize if possible 34 | foreach (KeyValuePair pair in types) 35 | { 36 | EqualsValueClauseSyntax value; 37 | if (values.TryGetValue(pair.Key, out value)) 38 | { 39 | ExpressionSyntax expression = value.Value; 40 | 41 | // If it's a literal, we can initialize it safely inside the struct 42 | if (m_context.Generators.Expression.IsLiteralExpression(expression.Kind())) 43 | { 44 | m_context.Generators.Expression.Generate(expression); 45 | m_context.Writer.AppendLine(","); 46 | } 47 | else 48 | { 49 | // Uninitialized for now 50 | m_context.Writer.AppendLine("0,"); 51 | } 52 | } 53 | else 54 | { 55 | // Uninitialized for now 56 | // About C: if a struct should be initialized to zeroes, we need {0} instead of 0 57 | ITypeSymbol typeSymbol = m_context.Model.GetTypeInfo(pair.Value).Type; 58 | if (!m_context.GenericTypeConvert.IsGeneric(typeSymbol) && typeSymbol.TypeKind == TypeKind.Struct) 59 | { 60 | m_context.Writer.AppendLine("{0},"); 61 | } 62 | else 63 | { 64 | m_context.Writer.AppendLine("0,"); 65 | } 66 | } 67 | } 68 | } 69 | 70 | /// 71 | /// Generates a struct member 72 | /// 73 | /// The name of the member 74 | /// The type of the member 75 | private void GenerateStructMember(string name, TypeSyntax type) 76 | { 77 | string typeName = m_context.ConvertTypeName(type); 78 | 79 | // Check if there's a variable initializer 80 | // If there is one, we need to change the type from pointer to array 81 | // so C knows that it needs to reserve memory 82 | if (m_classCode.staticFields.ContainsKey(name)) 83 | { 84 | ExpressionSyntax expression = m_classCode.staticFields[name].Value; 85 | if (expression.Kind() == SyntaxKind.ArrayInitializerExpression) 86 | { 87 | InitializerExpressionSyntax initializer = expression as InitializerExpressionSyntax; 88 | typeName = typeName.Substring(0, typeName.Length - 1); 89 | name += "[" + initializer.Expressions.Count() + "]"; 90 | } 91 | } 92 | 93 | // Check for extra modifiers 94 | IEnumerable tokens = type.Parent.Parent.ChildTokens(); 95 | foreach (SyntaxToken token in tokens) 96 | { 97 | if (token.Kind() == SyntaxKind.VolatileKeyword) 98 | { 99 | m_context.Writer.Append("volatile "); 100 | break; 101 | } 102 | } 103 | 104 | m_context.Writer.AppendLine(string.Format("{0} {1};", typeName, name)); 105 | } 106 | 107 | /// 108 | /// Generates the static fields class struct 109 | /// 110 | /// The class declaration 111 | public override void Generate(ClassDeclarationSyntax node) 112 | { 113 | // Are there even static fields? 114 | if (m_classCode.staticFieldTypes.Count == 0 && m_classCode.propertyTypesStatic.Count == 0) 115 | return; 116 | 117 | string convertedClassName = m_context.TypeConvert.ConvertClassName(node.Identifier.ToString()); 118 | 119 | m_context.Writer.AppendLine("struct"); 120 | m_context.Writer.AppendLine("{"); 121 | 122 | foreach (KeyValuePair pair in m_classCode.staticFieldTypes) 123 | { 124 | GenerateStructMember(pair.Key, pair.Value); 125 | } 126 | 127 | foreach (KeyValuePair pair in m_classCode.propertyTypesStatic) 128 | { 129 | GenerateStructMember("prop_" + pair.Key, pair.Value); 130 | } 131 | 132 | m_context.Writer.Append("} classStatics_"); 133 | m_context.Writer.Append(convertedClassName); 134 | 135 | // Initializers 136 | m_context.Writer.AppendLine(" = {"); 137 | m_context.Writer.Indent(); 138 | 139 | GenerateInitializer(m_classCode.staticFieldTypes, m_classCode.staticFields); 140 | GenerateInitializer(m_classCode.propertyTypesStatic, m_classCode.propertyInitialValuesStatic); 141 | 142 | m_context.Writer.UnIndent(); 143 | m_context.Writer.AppendLine("};"); 144 | } 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /LibCS2C/Generators/ClassStructGenerator.cs: -------------------------------------------------------------------------------- 1 | using LibCS2C.Context; 2 | using Microsoft.CodeAnalysis; 3 | using Microsoft.CodeAnalysis.CSharp; 4 | using Microsoft.CodeAnalysis.CSharp.Syntax; 5 | using System; 6 | using System.Collections.Generic; 7 | 8 | namespace LibCS2C.Generators 9 | { 10 | class ClassStructGenerator : GeneratorBase 11 | { 12 | private ClassCodeData m_classCode; 13 | 14 | /// 15 | /// Class struct generator 16 | /// 17 | /// The walker context 18 | /// Class code 19 | public ClassStructGenerator(WalkerContext context, ClassCodeData classCode) 20 | { 21 | m_context = context; 22 | m_classCode = classCode; 23 | } 24 | 25 | /// 26 | /// Generates the class struct 27 | /// 28 | /// The class declaration 29 | public override void Generate(ClassDeclarationSyntax node) 30 | { 31 | m_context.Writer.CurrentDestination = WriterDestination.ClassStructs; 32 | m_context.Writer.AppendLine(m_context.TypeConvert.CurrentClassStructName); 33 | m_context.Writer.AppendLine("{"); 34 | 35 | // For method lookup at runtime 36 | m_context.Writer.AppendLine("void** lookup_table;"); 37 | 38 | foreach (KeyValuePair pair in m_classCode.nonStaticFieldTypes) 39 | { 40 | // Check for extra modifiers 41 | IEnumerable tokens = pair.Value.Parent.Parent.ChildTokens(); 42 | foreach (SyntaxToken token in tokens) 43 | { 44 | if (token.Kind() == SyntaxKind.VolatileKeyword) 45 | { 46 | m_context.Writer.Append("volatile "); 47 | break; 48 | } 49 | } 50 | 51 | m_context.Writer.AppendLine(string.Format("{0} field_{1};", m_context.ConvertTypeName(pair.Value), pair.Key)); 52 | } 53 | 54 | // We need to keep the order of the base (with interfaces), so first generate those properties 55 | // and then generate the properties of this class that are not part of the interface 56 | // TODO: multiple levels of bases (?) 57 | BaseListSyntax baseList = node.BaseList; 58 | if (baseList != null) 59 | { 60 | IEnumerable nodes = baseList.ChildNodes(); 61 | foreach (SimpleBaseTypeSyntax child in nodes) 62 | { 63 | // Get base type 64 | ITypeSymbol typeSymbol = m_context.Model.GetTypeInfo(child.Type).Type; 65 | 66 | // Loop through interface properties 67 | InterfaceDeclarationSyntax interfaceDeclaration = typeSymbol.DeclaringSyntaxReferences[0].GetSyntax() as InterfaceDeclarationSyntax; 68 | IEnumerable interfaceNodes = node.ChildNodes(); 69 | foreach (SyntaxNode interfaceChild in interfaceNodes) 70 | { 71 | if (interfaceChild.Kind() == SyntaxKind.PropertyDeclaration) 72 | { 73 | PropertyDeclarationSyntax property = interfaceChild as PropertyDeclarationSyntax; 74 | m_context.Writer.AppendLine(string.Format("{0} prop_{1};", m_context.ConvertTypeName(property.Type), property.Identifier)); 75 | 76 | // Remove from list so we don't generate them twice 77 | m_classCode.propertyTypesNonStatic.Remove(property.Identifier.ToString()); 78 | } 79 | } 80 | } 81 | } 82 | 83 | foreach (KeyValuePair pair in m_classCode.propertyTypesNonStatic) 84 | { 85 | m_context.Writer.AppendLine(string.Format("{0} prop_{1};", m_context.ConvertTypeName(pair.Value), pair.Key)); 86 | } 87 | 88 | m_context.Writer.AppendLine("};"); 89 | 90 | m_context.Writer.CurrentDestination = WriterDestination.StructPrototypes; 91 | m_context.Writer.AppendLine(string.Format("{0};", m_context.TypeConvert.CurrentClassStructName)); 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /LibCS2C/Generators/ConditionalAccessExpressionGenerator.cs: -------------------------------------------------------------------------------- 1 | using LibCS2C.Context; 2 | using Microsoft.CodeAnalysis.CSharp.Syntax; 3 | 4 | namespace LibCS2C.Generators 5 | { 6 | public class ConditionalAccessExpressionGenerator : GeneratorBase 7 | { 8 | /// 9 | /// Conditional access expression generator 10 | /// 11 | /// The walker context 12 | public ConditionalAccessExpressionGenerator(WalkerContext context) 13 | { 14 | m_context = context; 15 | } 16 | 17 | /// 18 | /// Generates a conditional access expression generator 19 | /// 20 | /// The access expression 21 | public override void Generate(ConditionalAccessExpressionSyntax node) 22 | { 23 | m_context.Writer.Append("if(("); 24 | m_context.Generators.Expression.Generate(node.Expression); 25 | m_context.Writer.Append(") != NULL)"); 26 | 27 | m_context.Writer.AppendLine("{"); 28 | m_context.Writer.Indent(); 29 | 30 | m_context.Generators.Invocation.Generate(node.WhenNotNull as InvocationExpressionSyntax); 31 | m_context.Writer.AppendLine(";"); 32 | 33 | m_context.Writer.UnIndent(); 34 | m_context.Writer.AppendLine("}"); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /LibCS2C/Generators/DelegateDeclarationGenerator.cs: -------------------------------------------------------------------------------- 1 | using LibCS2C.Context; 2 | using Microsoft.CodeAnalysis; 3 | using Microsoft.CodeAnalysis.CSharp.Syntax; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Text; 8 | 9 | namespace LibCS2C.Generators 10 | { 11 | public class DelegateDeclarationGenerator : GeneratorBase 12 | { 13 | /// 14 | /// Delegate declaration generator 15 | /// 16 | /// The walker context 17 | public DelegateDeclarationGenerator(WalkerContext context) 18 | { 19 | m_context = context; 20 | } 21 | 22 | /// 23 | /// Generates a delegate declaration 24 | /// 25 | /// The delegate 26 | public override void Generate(DelegateDeclarationSyntax node) 27 | { 28 | WriterDestination destination = m_context.Writer.CurrentDestination; 29 | m_context.Writer.CurrentDestination = WriterDestination.Delegates; 30 | 31 | m_context.Writer.Append(string.Format("typedef {0} (*delegate_{1}_{2}) (", m_context.ConvertTypeName(node.ReturnType), m_context.TypeConvert.CurrentClassNameFormatted, node.Identifier)); 32 | 33 | IEnumerable paramNodes = node.ParameterList.ChildNodes(); 34 | foreach (ParameterSyntax paramNode in paramNodes) 35 | { 36 | m_context.Writer.Append(string.Format("{0} {1}", m_context.ConvertTypeName(paramNode.Type), paramNode.Identifier)); 37 | 38 | // A comma if it's not the last parameter 39 | if (paramNode != paramNodes.Last()) 40 | m_context.Writer.Append(", "); 41 | } 42 | 43 | m_context.Writer.AppendLine(");"); 44 | 45 | m_context.Writer.CurrentDestination = destination; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /LibCS2C/Generators/DoStatementGenerator.cs: -------------------------------------------------------------------------------- 1 | using LibCS2C.Context; 2 | using Microsoft.CodeAnalysis.CSharp.Syntax; 3 | 4 | namespace LibCS2C.Generators 5 | { 6 | public class DoStatementGenerator : GeneratorBase 7 | { 8 | /// 9 | /// Do statement generator 10 | /// 11 | /// The walker context 12 | public DoStatementGenerator(WalkerContext context) 13 | { 14 | m_context = context; 15 | } 16 | 17 | /// 18 | /// Generates a do statement 19 | /// 20 | /// The do statement 21 | public override void Generate(DoStatementSyntax node) 22 | { 23 | m_context.Writer.AppendLine("do"); 24 | m_context.Writer.AppendLine("{"); 25 | m_context.Writer.Indent(); 26 | m_context.Generators.Block.GenerateChild(node.Statement); 27 | m_context.Writer.UnIndent(); 28 | m_context.Writer.AppendLine("}"); 29 | m_context.Writer.Append("while("); 30 | m_context.Generators.Expression.Generate(node.Condition); 31 | m_context.Writer.Append(")"); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /LibCS2C/Generators/ElementAccessGenerator.cs: -------------------------------------------------------------------------------- 1 | using LibCS2C.Context; 2 | using Microsoft.CodeAnalysis; 3 | using Microsoft.CodeAnalysis.CSharp; 4 | using Microsoft.CodeAnalysis.CSharp.Syntax; 5 | using System.Collections.Generic; 6 | 7 | namespace LibCS2C.Generators 8 | { 9 | public class ElementAccessGenerator : GeneratorBase 10 | { 11 | /// 12 | /// Element access expression generator 13 | /// 14 | /// The walker context 15 | public ElementAccessGenerator(WalkerContext context) 16 | { 17 | m_context = context; 18 | } 19 | 20 | /// 21 | /// Generates an element access expression 22 | /// 23 | /// The expression 24 | public override void Generate(ElementAccessExpressionSyntax node) 25 | { 26 | m_context.Writer.ShouldOutputPost = true; 27 | 28 | IEnumerable nodes = node.ChildNodes(); 29 | foreach (SyntaxNode child in nodes) 30 | { 31 | SyntaxKind kind = child.Kind(); 32 | 33 | if (kind == SyntaxKind.IdentifierName) 34 | { 35 | ISymbol symbol = m_context.Model.GetSymbolInfo(child).Symbol; 36 | if (symbol.Kind == SymbolKind.Field && !symbol.IsStatic) 37 | m_context.Writer.Append("obj->"); 38 | 39 | m_context.Writer.Append(m_context.TypeConvert.ConvertVariableName(child)); 40 | } 41 | else if (kind == SyntaxKind.BracketedArgumentList) 42 | { 43 | BracketedArgumentListSyntax args = child as BracketedArgumentListSyntax; 44 | IEnumerable children = args.ChildNodes(); 45 | 46 | m_context.Writer.Append("["); 47 | 48 | foreach (ArgumentSyntax childNode in children) 49 | { 50 | m_context.Generators.Expression.Generate(childNode.Expression); 51 | } 52 | 53 | m_context.Writer.Append("]"); 54 | } 55 | else 56 | { 57 | m_context.Generators.Expression.Generate(child); 58 | } 59 | } 60 | 61 | m_context.Writer.ShouldOutputPost = false; 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /LibCS2C/Generators/EnumGenerator.cs: -------------------------------------------------------------------------------- 1 | using LibCS2C.Context; 2 | using Microsoft.CodeAnalysis; 3 | using Microsoft.CodeAnalysis.CSharp.Syntax; 4 | 5 | namespace LibCS2C.Generators 6 | { 7 | public class EnumGenerator : GeneratorBase 8 | { 9 | /// 10 | /// Enum statement generator 11 | /// 12 | /// The walker context 13 | public EnumGenerator(WalkerContext context) 14 | { 15 | m_context = context; 16 | } 17 | 18 | /// 19 | /// Generates an enum 20 | /// 21 | /// The enum 22 | public override void Generate(EnumDeclarationSyntax node) 23 | { 24 | WriterDestination destination = m_context.Writer.CurrentDestination; 25 | m_context.Writer.CurrentDestination = WriterDestination.Defines; 26 | 27 | bool insideClass = (node.Parent is ClassDeclarationSyntax); 28 | SeparatedSyntaxList nodes = node.Members; 29 | 30 | string lastValue = "0"; 31 | foreach (EnumMemberDeclarationSyntax child in nodes) 32 | { 33 | // Enum values are always ints 34 | string identifier = child.Identifier.ToString(); 35 | string currentValue = lastValue; 36 | if (child.EqualsValue != null) 37 | { 38 | currentValue = lastValue = child.EqualsValue.Value.ToString(); 39 | } 40 | 41 | lastValue += "+1"; 42 | if (insideClass) 43 | m_context.Writer.Append(string.Format("#define enum_{0}_{1}_{2}", m_context.TypeConvert.CurrentClassNameFormatted, node.Identifier, identifier)); 44 | else 45 | m_context.Writer.Append(string.Format("#define enum_{0}_{1}_{2}", m_context.TypeConvert.CurrentNamespaceFormatted, node.Identifier, identifier)); 46 | 47 | m_context.Writer.Append(" ("); 48 | m_context.Writer.CurrentDestination = WriterDestination.TempBuffer; 49 | m_context.Writer.Append(currentValue.ToString()); 50 | m_context.Writer.CurrentDestination = WriterDestination.Defines; 51 | m_context.Writer.Append(m_context.Writer.FlushTempBuffer()); 52 | m_context.Writer.AppendLine(")"); 53 | } 54 | 55 | m_context.Writer.CurrentDestination = destination; 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /LibCS2C/Generators/ExpressionGenerator.cs: -------------------------------------------------------------------------------- 1 | using LibCS2C.Context; 2 | using Microsoft.CodeAnalysis; 3 | using Microsoft.CodeAnalysis.CSharp; 4 | using Microsoft.CodeAnalysis.CSharp.Syntax; 5 | using System; 6 | using System.Linq; 7 | 8 | namespace LibCS2C.Generators 9 | { 10 | public class ExpressionGenerator : GeneratorBase 11 | { 12 | /// 13 | /// Expression generator 14 | /// 15 | /// The walker context 16 | public ExpressionGenerator(WalkerContext context) 17 | { 18 | m_context = context; 19 | } 20 | 21 | /// 22 | /// Generates the expression code 23 | /// 24 | /// The expression node 25 | public override void Generate(SyntaxNode node) 26 | { 27 | SyntaxKind kind = node.Kind(); 28 | 29 | switch (kind) 30 | { 31 | case SyntaxKind.ArrayCreationExpression: 32 | m_context.Generators.ArrayCreationExpression.Generate(node as ArrayCreationExpressionSyntax); 33 | break; 34 | 35 | case SyntaxKind.PointerMemberAccessExpression: 36 | m_context.Generators.PointerMemberAccessExpression.Generate(node as MemberAccessExpressionSyntax); 37 | break; 38 | 39 | case SyntaxKind.AddressOfExpression: 40 | m_context.Generators.AddressOfExpression.Generate(node as PrefixUnaryExpressionSyntax); 41 | break; 42 | 43 | case SyntaxKind.ElementAccessExpression: 44 | m_context.Generators.ElementAccess.Generate(node as ElementAccessExpressionSyntax); 45 | break; 46 | 47 | case SyntaxKind.SimpleMemberAccessExpression: 48 | m_context.Generators.SimpleMemberAccess.Generate(node as ExpressionSyntax); 49 | break; 50 | 51 | case SyntaxKind.ObjectCreationExpression: 52 | m_context.Generators.ObjectCreationExpression.Generate(node as ObjectCreationExpressionSyntax); 53 | break; 54 | 55 | case SyntaxKind.SimpleAssignmentExpression: 56 | m_context.Generators.SimpleAssignment.Generate(node as AssignmentExpressionSyntax); 57 | break; 58 | 59 | case SyntaxKind.InvocationExpression: 60 | m_context.Generators.Invocation.Generate(node as InvocationExpressionSyntax); 61 | break; 62 | 63 | case SyntaxKind.LeftShiftAssignmentExpression: 64 | m_context.Generators.LeftShiftAssignment.Generate(node as AssignmentExpressionSyntax); 65 | break; 66 | 67 | case SyntaxKind.RightShiftAssignmentExpression: 68 | m_context.Generators.RightShiftAssignment.Generate(node as AssignmentExpressionSyntax); 69 | break; 70 | 71 | case SyntaxKind.OrAssignmentExpression: 72 | m_context.Generators.BinaryOrAssignment.Generate(node as AssignmentExpressionSyntax); 73 | break; 74 | 75 | case SyntaxKind.AndAssignmentExpression: 76 | m_context.Generators.BinaryAndAssignment.Generate(node as AssignmentExpressionSyntax); 77 | break; 78 | 79 | case SyntaxKind.ExclusiveOrAssignmentExpression: 80 | m_context.Generators.ExclusiveOrAssignment.Generate(node as AssignmentExpressionSyntax); 81 | break; 82 | 83 | case SyntaxKind.AddAssignmentExpression: 84 | m_context.Generators.AddAssignment.Generate(node as AssignmentExpressionSyntax); 85 | break; 86 | 87 | case SyntaxKind.SubtractAssignmentExpression: 88 | m_context.Generators.SubstractAssignment.Generate(node as AssignmentExpressionSyntax); 89 | break; 90 | 91 | case SyntaxKind.MultiplyAssignmentExpression: 92 | m_context.Generators.MultiplyAssignment.Generate(node as AssignmentExpressionSyntax); 93 | break; 94 | 95 | case SyntaxKind.DivideAssignmentExpression: 96 | m_context.Generators.DivideAssignment.Generate(node as AssignmentExpressionSyntax); 97 | break; 98 | 99 | case SyntaxKind.ModuloAssignmentExpression: 100 | m_context.Generators.ModuloAssignment.Generate(node as AssignmentExpressionSyntax); 101 | break; 102 | 103 | case SyntaxKind.IdentifierName: 104 | m_context.Generators.IdentifierName.Generate(node as IdentifierNameSyntax); 105 | break; 106 | 107 | case SyntaxKind.CastExpression: 108 | m_context.Generators.CastExpression.Generate(node as CastExpressionSyntax); 109 | break; 110 | 111 | case SyntaxKind.SizeOfExpression: 112 | m_context.Generators.SizeOfExpression.Generate(node as SizeOfExpressionSyntax); 113 | break; 114 | 115 | case SyntaxKind.PostDecrementExpression: 116 | m_context.Generators.PostDecrementExpression.Generate(node as ExpressionSyntax); 117 | break; 118 | 119 | case SyntaxKind.PostIncrementExpression: 120 | m_context.Generators.PostIncrementExpression.Generate(node as ExpressionSyntax); 121 | break; 122 | 123 | case SyntaxKind.PreDecrementExpression: 124 | m_context.Generators.PreDecrementExpression.Generate(node as ExpressionSyntax); 125 | break; 126 | 127 | case SyntaxKind.PreIncrementExpression: 128 | m_context.Generators.PreIncrementExpression.Generate(node as ExpressionSyntax); 129 | break; 130 | 131 | case SyntaxKind.ConditionalAccessExpression: 132 | m_context.Generators.ConditionalAccessExpression.Generate(node as ConditionalAccessExpressionSyntax); 133 | break; 134 | 135 | case SyntaxKind.ThisExpression: 136 | m_context.Writer.Append("obj"); 137 | break; 138 | 139 | case SyntaxKind.TrueLiteralExpression: 140 | m_context.Writer.Append("1"); 141 | break; 142 | 143 | case SyntaxKind.FalseLiteralExpression: 144 | m_context.Writer.Append("0"); 145 | break; 146 | 147 | case SyntaxKind.NullLiteralExpression: 148 | m_context.Writer.Append("NULL"); 149 | break; 150 | 151 | case SyntaxKind.ArrayInitializerExpression: 152 | m_context.Generators.ArrayInitializerExpression.Generate(node as InitializerExpressionSyntax); 153 | break; 154 | 155 | default: 156 | if (IsSubExpression(kind) || IsLiteralExpression(kind)) 157 | { 158 | ChildSyntaxList children = node.ChildNodesAndTokens(); 159 | foreach (SyntaxNodeOrToken child in children) 160 | { 161 | SyntaxKind childKind = child.Kind(); 162 | 163 | if (child.IsToken) 164 | { 165 | m_context.Writer.Append(child.ToString()); 166 | } 167 | else 168 | { 169 | Generate(child.AsNode()); 170 | } 171 | } 172 | } 173 | else 174 | { 175 | throw new NotImplementedException("Unknown SyntaxKind in Expression: " + node.Kind()); 176 | } 177 | 178 | break; 179 | } 180 | } 181 | 182 | /// 183 | /// Checks if the syntax node kind is a sub expression 184 | /// 185 | /// The syntax kind 186 | /// If it's a sub expression 187 | public bool IsSubExpression(SyntaxKind kind) 188 | { 189 | SyntaxKind[] kinds = { SyntaxKind.AddExpression, SyntaxKind.CastExpression, SyntaxKind.SubtractExpression, SyntaxKind.MultiplyExpression, SyntaxKind.DivideExpression, SyntaxKind.BitwiseAndExpression, SyntaxKind.BitwiseNotExpression, SyntaxKind.BitwiseOrExpression, SyntaxKind.ExclusiveOrExpression, SyntaxKind.EqualsExpression, SyntaxKind.NotEqualsExpression, SyntaxKind.ElementAccessExpression, SyntaxKind.LessThanExpression, SyntaxKind.LessThanOrEqualExpression, SyntaxKind.GreaterThanExpression, SyntaxKind.GreaterThanOrEqualExpression, SyntaxKind.ParenthesizedExpression, SyntaxKind.SimpleMemberAccessExpression, SyntaxKind.SimpleAssignmentExpression, SyntaxKind.ObjectCreationExpression, SyntaxKind.ArrayCreationExpression, SyntaxKind.AddressOfExpression, SyntaxKind.InvocationExpression, SyntaxKind.LogicalAndExpression, SyntaxKind.LogicalNotExpression, SyntaxKind.LogicalOrExpression, SyntaxKind.ConditionalExpression, SyntaxKind.PointerMemberAccessExpression, SyntaxKind.RightShiftExpression, SyntaxKind.LeftShiftExpression, SyntaxKind.PreDecrementExpression, SyntaxKind.PreIncrementExpression, SyntaxKind.PostDecrementExpression, SyntaxKind.PostIncrementExpression, SyntaxKind.UnaryMinusExpression, SyntaxKind.UnaryPlusExpression, SyntaxKind.ModuloExpression, SyntaxKind.PointerIndirectionExpression, SyntaxKind.ThisExpression, SyntaxKind.ArrayType }; 190 | return kinds.Contains(kind); 191 | } 192 | 193 | /// 194 | /// Checks if the given kind is a literal expression 195 | /// 196 | /// The kind 197 | /// If it's a literal expression 198 | public bool IsLiteralExpression(SyntaxKind kind) 199 | { 200 | SyntaxKind[] kinds = { SyntaxKind.CharacterLiteralExpression, SyntaxKind.NullLiteralExpression, SyntaxKind.FalseLiteralExpression, SyntaxKind.TrueLiteralExpression, SyntaxKind.StringLiteralExpression, SyntaxKind.NumericLiteralExpression, SyntaxKind.NullLiteralExpression, SyntaxKind.ArrayInitializerExpression }; 201 | return kinds.Contains(kind); 202 | } 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /LibCS2C/Generators/ExpressionStatementGenerator.cs: -------------------------------------------------------------------------------- 1 | using LibCS2C.Context; 2 | using Microsoft.CodeAnalysis.CSharp.Syntax; 3 | 4 | namespace LibCS2C.Generators 5 | { 6 | public class ExpressionStatementGenerator : GeneratorBase 7 | { 8 | /// 9 | /// Expression generator 10 | /// 11 | /// The walker context 12 | public ExpressionStatementGenerator(WalkerContext context) 13 | { 14 | m_context = context; 15 | } 16 | 17 | /// 18 | /// Generates the expression code 19 | /// 20 | /// The expression statement node 21 | public override void Generate(ExpressionStatementSyntax node) 22 | { 23 | m_context.Generators.Expression.Generate(node.Expression); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /LibCS2C/Generators/FixedStatementGenerator.cs: -------------------------------------------------------------------------------- 1 | using LibCS2C.Context; 2 | using Microsoft.CodeAnalysis; 3 | using Microsoft.CodeAnalysis.CSharp.Syntax; 4 | using System.Collections.Generic; 5 | 6 | namespace LibCS2C.Generators 7 | { 8 | public class FixedStatementGenerator : GeneratorBase 9 | { 10 | /// 11 | /// Fixed statement generator 12 | /// 13 | /// The walker context 14 | public FixedStatementGenerator(WalkerContext context) 15 | { 16 | m_context = context; 17 | } 18 | 19 | /// 20 | /// Generates a fixed statement 21 | /// 22 | /// The fixed statement 23 | public override void Generate(FixedStatementSyntax node) 24 | { 25 | m_context.Writer.AppendLine("{"); 26 | m_context.Writer.Indent(); 27 | 28 | IEnumerable children = node.ChildNodes(); 29 | foreach (SyntaxNode child in children) 30 | { 31 | m_context.Generators.Block.GenerateChild(child); 32 | } 33 | 34 | m_context.Writer.UnIndent(); 35 | m_context.Writer.AppendLine("}"); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /LibCS2C/Generators/ForStatementGenerator.cs: -------------------------------------------------------------------------------- 1 | using LibCS2C.Context; 2 | using Microsoft.CodeAnalysis; 3 | using Microsoft.CodeAnalysis.CSharp.Syntax; 4 | 5 | namespace LibCS2C.Generators 6 | { 7 | public class ForStatementGenerator : GeneratorBase 8 | { 9 | /// 10 | /// For statement generator 11 | /// 12 | /// The walker context 13 | public ForStatementGenerator(WalkerContext context) 14 | { 15 | m_context = context; 16 | } 17 | 18 | /// 19 | /// Generates a for statement 20 | /// 21 | /// The for statement 22 | public override void Generate(ForStatementSyntax node) 23 | { 24 | m_context.Writer.Append("for("); 25 | 26 | // Declaration 27 | if (node.Declaration != null) 28 | m_context.Generators.Variable.Generate(node.Declaration); 29 | 30 | m_context.Writer.Append(";"); 31 | 32 | // Condition 33 | if (node.Condition != null) 34 | m_context.Generators.Expression.Generate(node.Condition); 35 | 36 | m_context.Writer.Append(";"); 37 | 38 | // Incrementors 39 | SeparatedSyntaxList nodes = node.Incrementors; 40 | foreach (ExpressionSyntax expression in nodes) 41 | { 42 | m_context.Generators.Expression.Generate(expression); 43 | } 44 | 45 | m_context.Writer.AppendLine(")"); 46 | 47 | // Code inside the loop 48 | if (node.Statement != null) 49 | { 50 | m_context.Writer.AppendLine("{"); 51 | m_context.Writer.Indent(); 52 | m_context.Generators.Block.GenerateChild(node.Statement); 53 | m_context.Writer.UnIndent(); 54 | m_context.Writer.AppendLine("}"); 55 | } 56 | else 57 | { 58 | m_context.Writer.AppendLine(";"); 59 | } 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /LibCS2C/Generators/GeneratorBase.cs: -------------------------------------------------------------------------------- 1 | using LibCS2C.Context; 2 | 3 | namespace LibCS2C.Generators 4 | { 5 | public abstract class GeneratorBase : IGenerator where T: class 6 | { 7 | protected WalkerContext m_context; 8 | 9 | public abstract void Generate(T node); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /LibCS2C/Generators/GotoStatementGenerator.cs: -------------------------------------------------------------------------------- 1 | using LibCS2C.Context; 2 | using Microsoft.CodeAnalysis.CSharp.Syntax; 3 | 4 | namespace LibCS2C.Generators 5 | { 6 | public class GotoStatementGenerator : GeneratorBase 7 | { 8 | /// 9 | /// Goto statement generator 10 | /// 11 | /// The walker context 12 | public GotoStatementGenerator(WalkerContext context) 13 | { 14 | m_context = context; 15 | } 16 | 17 | /// 18 | /// Generates a goto statement 19 | /// 20 | /// The goto statement 21 | public override void Generate(GotoStatementSyntax node) 22 | { 23 | m_context.Writer.Append(string.Format("goto {0}", node.Expression)); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /LibCS2C/Generators/IGenerator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace LibCS2C.Generators 8 | { 9 | interface IGenerator where T: class 10 | { 11 | void Generate(T node); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /LibCS2C/Generators/IdentifierNameGenerator.cs: -------------------------------------------------------------------------------- 1 | using LibCS2C.Context; 2 | using Microsoft.CodeAnalysis; 3 | using Microsoft.CodeAnalysis.CSharp.Syntax; 4 | using System; 5 | 6 | namespace LibCS2C.Generators 7 | { 8 | public class IdentifierNameGenerator : GeneratorBase 9 | { 10 | /// 11 | /// Identifier name generator 12 | /// 13 | /// The walker context 14 | public IdentifierNameGenerator(WalkerContext context) 15 | { 16 | m_context = context; 17 | } 18 | 19 | /// 20 | /// Generate code for identifier name 21 | /// 22 | /// 23 | public override void Generate(IdentifierNameSyntax node) 24 | { 25 | ISymbol symbol = m_context.Model.GetSymbolInfo(node).Symbol; 26 | if (symbol == null) 27 | throw new Exception("Could not get the symbol info of: " + node); 28 | 29 | if (symbol.Kind == SymbolKind.Field && !symbol.IsStatic) 30 | m_context.Writer.Append("obj->"); 31 | 32 | m_context.Writer.Append(m_context.TypeConvert.ConvertVariableName(node)); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /LibCS2C/Generators/IfStatementGenerator.cs: -------------------------------------------------------------------------------- 1 | using LibCS2C.Context; 2 | using Microsoft.CodeAnalysis; 3 | using Microsoft.CodeAnalysis.CSharp; 4 | using Microsoft.CodeAnalysis.CSharp.Syntax; 5 | using System.Linq; 6 | 7 | namespace LibCS2C.Generators 8 | { 9 | public class IfStatementGenerator : GeneratorBase 10 | { 11 | /// 12 | /// If statement generator 13 | /// 14 | /// The walker context 15 | public IfStatementGenerator(WalkerContext context) 16 | { 17 | m_context = context; 18 | } 19 | 20 | /// 21 | /// Generates an if statement 22 | /// 23 | /// The if statement 24 | public override void Generate(IfStatementSyntax node) 25 | { 26 | ChildSyntaxList list = node.ChildNodesAndTokens(); 27 | 28 | foreach (SyntaxNodeOrToken child in list) 29 | { 30 | SyntaxKind kind = child.Kind(); 31 | 32 | // Node 33 | if (child.IsNode) 34 | { 35 | SyntaxNode childNode = child.AsNode(); 36 | 37 | if (m_context.Generators.Expression.IsSubExpression(kind)) 38 | { 39 | m_context.Generators.Expression.Generate(childNode); 40 | } 41 | else if (kind == SyntaxKind.ElseClause) 42 | { 43 | SyntaxNode firstNode = childNode.ChildNodes().First(); 44 | SyntaxKind childKind = firstNode.Kind(); 45 | 46 | if (childKind == SyntaxKind.IfStatement) 47 | { 48 | m_context.Writer.Append("else "); 49 | Generate(firstNode as IfStatementSyntax); 50 | } 51 | else 52 | { 53 | m_context.Writer.AppendLine("else"); 54 | 55 | SyntaxNode first = childNode.ChildNodes().First(); 56 | SyntaxKind firstKind = first.Kind(); 57 | 58 | m_context.Writer.AppendLine("{"); 59 | if (firstKind == SyntaxKind.Block) 60 | { 61 | m_context.Generators.Block.Generate(first as BlockSyntax); 62 | } 63 | else 64 | { 65 | m_context.Writer.Indent(); 66 | m_context.Generators.Block.GenerateChild(first); 67 | m_context.Writer.UnIndent(); 68 | } 69 | m_context.Writer.AppendLine("}"); 70 | } 71 | } 72 | else if (kind == SyntaxKind.Block) 73 | { 74 | m_context.Writer.AppendLine("{"); 75 | m_context.Generators.Block.Generate(childNode as BlockSyntax); 76 | m_context.Writer.AppendLine("}"); 77 | } 78 | else 79 | { 80 | m_context.Writer.AppendLine(""); 81 | m_context.Writer.AppendIndent(); 82 | m_context.Generators.Block.GenerateChild(childNode); 83 | } 84 | } 85 | // Token, just emit it 86 | else 87 | { 88 | m_context.Writer.Append(child.ToString()); 89 | } 90 | } 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /LibCS2C/Generators/InterfaceGenerator.cs: -------------------------------------------------------------------------------- 1 | using LibCS2C.Context; 2 | using Microsoft.CodeAnalysis; 3 | using Microsoft.CodeAnalysis.CSharp; 4 | using Microsoft.CodeAnalysis.CSharp.Syntax; 5 | using System.Collections.Generic; 6 | 7 | namespace LibCS2C.Generators 8 | { 9 | public class InterfaceGenerator : GeneratorBase 10 | { 11 | /// 12 | /// interface generator 13 | /// 14 | /// The walker context 15 | public InterfaceGenerator(WalkerContext context) 16 | { 17 | m_context = context; 18 | } 19 | 20 | /// 21 | /// Generates an interface declaration 22 | /// 23 | /// The interface declaration 24 | public override void Generate(InterfaceDeclarationSyntax node) 25 | { 26 | string structName = "struct " + m_context.TypeConvert.ConvertClassName(node.Identifier.ToString()); 27 | 28 | m_context.Writer.CurrentDestination = WriterDestination.ClassStructs; 29 | m_context.Writer.AppendLine(structName); 30 | m_context.Writer.AppendLine("{"); 31 | 32 | // For method lookup at runtime 33 | m_context.Writer.AppendLine("void** lookup_table;"); 34 | 35 | IEnumerable nodes = node.ChildNodes(); 36 | foreach (SyntaxNode child in nodes) 37 | { 38 | if (child.Kind() == SyntaxKind.PropertyDeclaration) 39 | { 40 | PropertyDeclarationSyntax property = child as PropertyDeclarationSyntax; 41 | m_context.Writer.AppendLine(string.Format("{0} prop_{1};", m_context.ConvertTypeName(property.Type), property.Identifier)); 42 | } 43 | } 44 | 45 | m_context.Writer.AppendLine("};"); 46 | 47 | m_context.Writer.CurrentDestination = WriterDestination.StructPrototypes; 48 | m_context.Writer.AppendLine(structName + ";"); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /LibCS2C/Generators/InvocationGenerator.cs: -------------------------------------------------------------------------------- 1 | using LibCS2C.Context; 2 | using Microsoft.CodeAnalysis; 3 | using Microsoft.CodeAnalysis.CSharp; 4 | using Microsoft.CodeAnalysis.CSharp.Syntax; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Collections.Immutable; 8 | using System.Linq; 9 | 10 | namespace LibCS2C.Generators 11 | { 12 | public class InvocationGenerator : GeneratorBase 13 | { 14 | /// 15 | /// Invocation generator 16 | /// 17 | /// The walker context 18 | public InvocationGenerator(WalkerContext context) 19 | { 20 | m_context = context; 21 | } 22 | 23 | /// 24 | /// Generates the object part 25 | /// 26 | /// The node for the object 27 | /// The object part 28 | private string GenerateObjectPart(SyntaxNode node) 29 | { 30 | IEnumerable children = node.ChildNodes(); 31 | if (children.Count() == 0) 32 | { 33 | return "obj"; 34 | } 35 | else 36 | { 37 | SyntaxNode firstChild = children.First(); 38 | SyntaxKind firstChildKind = firstChild.Kind(); 39 | 40 | // OBJECT.METHOD(...) 41 | if (firstChildKind == SyntaxKind.IdentifierName) 42 | { 43 | WriterDestination destination = m_context.Writer.CurrentDestination; 44 | m_context.Writer.CurrentDestination = WriterDestination.TempBuffer; 45 | m_context.Generators.Expression.Generate(firstChild); 46 | m_context.Writer.CurrentDestination = destination; 47 | return m_context.Writer.FlushTempBuffer(); 48 | } 49 | // base.METHOD(...) 50 | else if (firstChildKind == SyntaxKind.BaseExpression) 51 | { 52 | return "(void*)obj"; 53 | } 54 | else 55 | { 56 | WriterDestination destination = m_context.Writer.CurrentDestination; 57 | m_context.Writer.CurrentDestination = WriterDestination.TempBuffer; 58 | m_context.Generators.Expression.Generate(firstChild as ExpressionSyntax); 59 | m_context.Writer.CurrentDestination = destination; 60 | return m_context.Writer.FlushTempBuffer(); 61 | } 62 | } 63 | } 64 | 65 | /// 66 | /// Generates an invocation 67 | /// 68 | /// The expression 69 | public override void Generate(InvocationExpressionSyntax node) 70 | { 71 | IEnumerable nodes = node.ChildNodes(); 72 | SyntaxNode first = nodes.First(); 73 | ISymbol firstSymbol = m_context.Model.GetSymbolInfo(first).Symbol; 74 | SyntaxKind firstKind = first.Kind(); 75 | 76 | bool needsObjReference = false; 77 | bool useFunctionPointer = false; 78 | 79 | // Arguments 80 | ArgumentListSyntax argsList = node.ArgumentList; 81 | int argCount = argsList.ChildNodes().Count(); 82 | 83 | // Member binding expression call 84 | if (firstKind == SyntaxKind.MemberBindingExpression) 85 | { 86 | // .Invoke is special 87 | // TODO: better way for doing this 88 | if (first.ToString().Equals(".Invoke")) 89 | { 90 | m_context.Generators.Expression.Generate(node.Parent.ChildNodes().First()); 91 | } 92 | // Normal call 93 | else 94 | { 95 | SyntaxNode type = first.ChildNodes().First(); 96 | 97 | ISymbol sym = m_context.Model.GetSymbolInfo(type).Symbol; 98 | string lookFor = sym.ContainingType.ToString().Replace('.', '_'); 99 | useFunctionPointer = (sym.Kind == SymbolKind.Method && (m_context.TypeIsExtending.ContainsKey(lookFor) && m_context.TypeIsExtending[lookFor])); 100 | 101 | if (useFunctionPointer) 102 | { 103 | needsObjReference = true; 104 | 105 | MethodDeclarationSyntax methodDeclaration = sym.DeclaringSyntaxReferences[0].GetSyntax() as MethodDeclarationSyntax; 106 | string prototype = m_context.TypeConvert.ConvertVariableName(first); 107 | 108 | first = node.Parent; 109 | m_context.Writer.Append(string.Format("((fp_{0})({1}->lookup_table[{2}])", prototype, GenerateObjectPart(first), m_context.MethodTable.GetID(lookFor, methodDeclaration))); 110 | } 111 | else 112 | { 113 | m_context.Writer.Append(m_context.TypeConvert.ConvertVariableName(first.ChildNodes().First())); 114 | 115 | m_context.Writer.Append("((void*)"); 116 | m_context.Generators.Expression.Generate(node.Parent.ChildNodes().First()); 117 | m_context.Writer.Append(")"); 118 | } 119 | } 120 | } 121 | // Normal method call 122 | else 123 | { 124 | ImmutableArray references; 125 | IMethodSymbol methodSym = null; 126 | string prototype = null; 127 | SyntaxNode reference = null; 128 | 129 | if (firstSymbol != null) 130 | { 131 | references = firstSymbol.DeclaringSyntaxReferences; 132 | 133 | if (firstSymbol.Kind == SymbolKind.Method) 134 | { 135 | methodSym = firstSymbol as IMethodSymbol; 136 | needsObjReference = !methodSym.IsStatic; 137 | prototype = m_context.Generators.MethodDeclaration.CreateMethodPrototype(methodSym, false, false); 138 | } 139 | else if (firstSymbol.Kind == SymbolKind.Property) 140 | { 141 | needsObjReference = false; 142 | prototype = m_context.TypeConvert.ConvertVariableName(first); 143 | } 144 | else 145 | { 146 | // Handled by code below 147 | } 148 | 149 | if (references.Length > 0) 150 | reference = references[0].GetSyntax(); 151 | } 152 | 153 | if (references == null || (reference != null && reference.Kind() == SyntaxKind.VariableDeclarator)) 154 | { 155 | foreach (SyntaxNode child in node.ChildNodes()) 156 | { 157 | SyntaxKind childKind = child.Kind(); 158 | if (m_context.Generators.Expression.IsSubExpression(childKind)) 159 | m_context.Generators.Expression.Generate(child); 160 | } 161 | } 162 | else 163 | { 164 | SyntaxNode type = (first.Kind() == SyntaxKind.IdentifierName) ? first : first.ChildNodes().First(); 165 | 166 | // If the type of the reference is an interface, we need to use the lookup table 167 | // If there are classes that extend the type of the reference, we need to use the lookup table 168 | // Else, we can call it directly 169 | ITypeSymbol typeOfReference = m_context.Model.GetTypeInfo(type).Type; 170 | if (typeOfReference == null) 171 | { 172 | m_context.Writer.Append(prototype); 173 | } 174 | else 175 | { 176 | MethodDeclarationSyntax methodDeclaration = reference as MethodDeclarationSyntax; 177 | string lookFor = string.Format("{0}_{1}", m_context.ConvertNameSpace(typeOfReference.ContainingNamespace), typeOfReference.Name); 178 | useFunctionPointer = (typeOfReference.TypeKind == TypeKind.Interface || (m_context.TypeIsExtending.ContainsKey(lookFor) && m_context.TypeIsExtending[lookFor])); 179 | 180 | if (useFunctionPointer) 181 | { 182 | m_context.Writer.Append(string.Format("((fp_{0})({1}->lookup_table[{2}])", prototype, GenerateObjectPart(first), m_context.MethodTable.GetID(lookFor, methodDeclaration))); 183 | } 184 | else 185 | { 186 | m_context.Writer.Append(prototype); 187 | 188 | if (firstSymbol.Kind == SymbolKind.Property && type != first) 189 | { 190 | m_context.Writer.Append("("); 191 | m_context.Generators.Expression.Generate(type); 192 | m_context.Writer.Append(")"); 193 | } 194 | } 195 | } 196 | } 197 | } 198 | 199 | if (useFunctionPointer) 200 | m_context.Writer.Append(")"); 201 | 202 | m_context.Writer.Append("("); 203 | 204 | // Reference to the object if needed 205 | if (needsObjReference) 206 | { 207 | string objName = GenerateObjectPart(first); 208 | 209 | // Argument for the object reference 210 | m_context.Writer.Append(objName); 211 | if (argsList.Arguments.Count() > 0) 212 | m_context.Writer.Append(", "); 213 | } 214 | 215 | m_context.Generators.ArgumentList.Generate(argsList); 216 | 217 | m_context.Writer.Append(")"); 218 | } 219 | } 220 | } 221 | -------------------------------------------------------------------------------- /LibCS2C/Generators/LabeledStatementGenerator.cs: -------------------------------------------------------------------------------- 1 | using LibCS2C.Context; 2 | using Microsoft.CodeAnalysis.CSharp.Syntax; 3 | 4 | namespace LibCS2C.Generators 5 | { 6 | public class LabeledStatementGenerator : GeneratorBase 7 | { 8 | /// 9 | /// Labeled statement generator 10 | /// 11 | /// The walker context 12 | public LabeledStatementGenerator(WalkerContext context) 13 | { 14 | m_context = context; 15 | } 16 | 17 | /// 18 | /// Generates a labeled statement 19 | /// 20 | /// The labeled statement 21 | public override void Generate(LabeledStatementSyntax node) 22 | { 23 | m_context.Writer.AppendLine(string.Format("{0}:", node.Identifier)); 24 | 25 | // Code inside the label 26 | if (node.Statement != null) 27 | { 28 | m_context.Writer.AppendLine("{"); 29 | m_context.Writer.Indent(); 30 | m_context.Generators.Block.GenerateChild(node.Statement); 31 | m_context.Writer.UnIndent(); 32 | m_context.Writer.AppendLine("}"); 33 | } 34 | else 35 | { 36 | m_context.Writer.AppendLine(";"); 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /LibCS2C/Generators/LocalDeclarationGenerator.cs: -------------------------------------------------------------------------------- 1 | using LibCS2C.Context; 2 | using Microsoft.CodeAnalysis; 3 | using Microsoft.CodeAnalysis.CSharp; 4 | using Microsoft.CodeAnalysis.CSharp.Syntax; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | 11 | namespace LibCS2C.Generators 12 | { 13 | public class LocalDeclarationGenerator : GeneratorBase 14 | { 15 | /// 16 | /// Local declaration generator 17 | /// 18 | /// The walker context 19 | public LocalDeclarationGenerator(WalkerContext context) 20 | { 21 | m_context = context; 22 | } 23 | 24 | /// 25 | /// Generates the local declaration 26 | /// 27 | /// The local declaration node 28 | public override void Generate(LocalDeclarationStatementSyntax node) 29 | { 30 | IEnumerable nodes = node.ChildNodes(); 31 | foreach (VariableDeclarationSyntax child in nodes) 32 | { 33 | m_context.Generators.Variable.Generate(child); 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /LibCS2C/Generators/ObjectCreationExpressionGenerator.cs: -------------------------------------------------------------------------------- 1 | using LibCS2C.Context; 2 | using Microsoft.CodeAnalysis; 3 | using Microsoft.CodeAnalysis.CSharp.Syntax; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | 8 | namespace LibCS2C.Generators 9 | { 10 | public class ObjectCreationExpressionGenerator : GeneratorBase 11 | { 12 | /// 13 | /// Object creation expression generator 14 | /// 15 | /// The walker context 16 | public ObjectCreationExpressionGenerator(WalkerContext context) 17 | { 18 | m_context = context; 19 | } 20 | 21 | /// 22 | /// Generates the expression code 23 | /// 24 | /// The expression statement node 25 | public override void Generate(ObjectCreationExpressionSyntax node) 26 | { 27 | IEnumerable objNodes = node.ChildNodes(); 28 | 29 | ArgumentListSyntax args = node.ArgumentList; 30 | ITypeSymbol type = m_context.Model.GetTypeInfo(node).Type; 31 | string nameSpace = type.ContainingNamespace.ToString().Replace(".", "_"); 32 | 33 | // Class 34 | if (type.TypeKind == TypeKind.Class) 35 | { 36 | IMethodSymbol symbol = m_context.Model.GetSymbolInfo(node).Symbol as IMethodSymbol; 37 | // A .ctor will have "specialname" metadata, IsExtensionMethod will return true if "specialname" metadata is set 38 | bool hasConstructor = (!symbol.IsImplicitlyDeclared); 39 | 40 | // Call constructor 41 | if (hasConstructor) 42 | { 43 | m_context.Writer.Append(m_context.Generators.MethodDeclaration.CreateMethodPrototype(symbol, false, false)); 44 | m_context.Writer.Append("("); 45 | } 46 | 47 | // Class initialization (returns the object, we can pass it as an argument to the constructor) 48 | m_context.Writer.Append(string.Format("classInit_{0}_{1}()", nameSpace, type.Name)); 49 | 50 | // Remaining arguments (if constructor) 51 | if (hasConstructor) 52 | { 53 | int argCount = args.ChildNodes().Count(); 54 | if (argCount > 0) 55 | m_context.Writer.Append(", "); 56 | 57 | m_context.Generators.ArgumentList.Generate(args); 58 | m_context.Writer.Append(")"); 59 | } 60 | } 61 | // Struct 62 | else 63 | { 64 | m_context.Writer.Append(string.Format("structInit_{0}_{1}()", type.ContainingSymbol.ToString().Replace(".", "_"), type.Name)); 65 | } 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /LibCS2C/Generators/PointerMemberAccessGenerator.cs: -------------------------------------------------------------------------------- 1 | using LibCS2C.Context; 2 | using Microsoft.CodeAnalysis; 3 | using Microsoft.CodeAnalysis.CSharp; 4 | using Microsoft.CodeAnalysis.CSharp.Syntax; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Text; 9 | 10 | namespace LibCS2C.Generators 11 | { 12 | public class PointerMemberAccessGenerator : GeneratorBase 13 | { 14 | /// 15 | /// PointerMemberAccess expression generator 16 | /// 17 | /// The walker context 18 | public PointerMemberAccessGenerator(WalkerContext context) 19 | { 20 | m_context = context; 21 | } 22 | 23 | /// 24 | /// Generates a PointerMemberAccess 25 | /// 26 | /// The PointerMemberAccess node 27 | public override void Generate(MemberAccessExpressionSyntax node) 28 | { 29 | ChildSyntaxList children = node.ChildNodesAndTokens(); 30 | 31 | ISymbol symbol = m_context.Model.GetSymbolInfo(node).Symbol; 32 | if (symbol.Kind == SymbolKind.Property) 33 | { 34 | m_context.Writer.Append(m_context.TypeConvert.ConvertVariableName(node)); 35 | m_context.Writer.Append("("); 36 | m_context.Generators.Expression.Generate(node.ChildNodes().First()); 37 | m_context.Writer.Append(")"); 38 | } 39 | else 40 | { 41 | bool first = true; 42 | foreach (SyntaxNodeOrToken child in children) 43 | { 44 | SyntaxKind childKind = child.Kind(); 45 | if (childKind == SyntaxKind.MinusGreaterThanToken) 46 | { 47 | m_context.Writer.Append("->"); 48 | } 49 | else if (childKind == SyntaxKind.IdentifierName) 50 | { 51 | ISymbol firstSymbol = m_context.Model.GetSymbolInfo(child.AsNode()).Symbol; 52 | if (firstSymbol != null && (!firstSymbol.IsStatic && firstSymbol.Kind == SymbolKind.Field) && first) 53 | m_context.Writer.Append("obj->"); 54 | 55 | m_context.Writer.Append(m_context.TypeConvert.ConvertVariableName(child.AsNode())); 56 | } 57 | else 58 | { 59 | m_context.Generators.Expression.Generate(child.AsNode()); 60 | } 61 | 62 | first = false; 63 | } 64 | } 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /LibCS2C/Generators/PrePostExpressionGenerator.cs: -------------------------------------------------------------------------------- 1 | using LibCS2C.Context; 2 | using Microsoft.CodeAnalysis; 3 | using Microsoft.CodeAnalysis.CSharp; 4 | using Microsoft.CodeAnalysis.CSharp.Syntax; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | 8 | namespace LibCS2C.Generators 9 | { 10 | public enum ExpressionType 11 | { 12 | PreIncrement, 13 | PreDecrement, 14 | PostIncrement, 15 | PostDecrement 16 | } 17 | 18 | public class PrePostExpressionGenerator : GeneratorBase 19 | { 20 | private ExpressionType m_expressionType; 21 | private bool m_isPost; 22 | private string m_type; 23 | private string m_shortType; 24 | 25 | /// 26 | /// Post expression generator 27 | /// 28 | /// The walker context 29 | /// Expression type 30 | public PrePostExpressionGenerator(WalkerContext context, ExpressionType expressionType) 31 | { 32 | m_context = context; 33 | m_expressionType = expressionType; 34 | 35 | m_isPost = (expressionType == ExpressionType.PostIncrement || expressionType == ExpressionType.PostDecrement); 36 | 37 | if (expressionType == ExpressionType.PreIncrement || expressionType == ExpressionType.PostIncrement) 38 | { 39 | m_type = "+1"; 40 | m_shortType = "++"; 41 | } 42 | else 43 | { 44 | m_type = "-1"; 45 | m_shortType = "--"; 46 | } 47 | } 48 | 49 | /// 50 | /// Generates the expression 51 | /// 52 | /// The expression 53 | public override void Generate(ExpressionSyntax node) 54 | { 55 | SyntaxNode name = node.ChildNodes().First(); 56 | ISymbol symbol = m_context.Model.GetSymbolInfo(name).Symbol; 57 | 58 | bool isProperty = (symbol != null && symbol.Kind == SymbolKind.Property); 59 | 60 | WriterDestination originalDestination = m_context.Writer.CurrentDestination; 61 | 62 | // Property 63 | if (isProperty) 64 | { 65 | // Set future value in post code 66 | bool doFutureValue = (m_isPost || m_context.Writer.ShouldOutputPost); 67 | if (doFutureValue) 68 | m_context.Writer.CurrentDestination = WriterDestination.PostBuffer; 69 | 70 | string getter; 71 | if (symbol.IsStatic) 72 | { 73 | getter = string.Format("{0}_{1}_getter()", symbol.ContainingType.ToString().Replace(".", "_"), symbol.Name); 74 | m_context.Writer.Append(string.Format("{0}_{1}_setter({2}{3})", symbol.ContainingType.ToString().Replace(".", "_"), symbol.Name, getter, m_type)); 75 | } 76 | else 77 | { 78 | string objectName = "obj"; 79 | IEnumerable nodes = name.ChildNodes(); 80 | if (nodes.Count() > 1) 81 | objectName = m_context.TypeConvert.ConvertVariableName(nodes.First()); 82 | 83 | getter = string.Format("{0}_{1}_getter({2})", symbol.ContainingType.ToString().Replace(".", "_"), symbol.Name, objectName); 84 | m_context.Writer.Append(string.Format("{0}_{1}_setter({4}, {2}{3})", symbol.ContainingType.ToString().Replace(".", "_"), symbol.Name, getter, m_type, objectName)); 85 | } 86 | 87 | if (m_isPost) 88 | m_context.Writer.CurrentDestination = originalDestination; 89 | 90 | // Only get the value if we're part of another expression 91 | if (doFutureValue && (node.Parent.Parent is ExpressionSyntax || node.Parent.Parent.Kind() == SyntaxKind.BracketedArgumentList)) 92 | m_context.Writer.Append(string.Format("{0}", getter)); 93 | } 94 | // Variable 95 | else 96 | { 97 | WriterDestination destinationVariable = m_context.Writer.CurrentDestination; 98 | m_context.Writer.CurrentDestination = WriterDestination.TempBuffer; 99 | m_context.Generators.Expression.Generate(name); 100 | string variable = m_context.Writer.FlushTempBuffer(); 101 | m_context.Writer.CurrentDestination = destinationVariable; 102 | 103 | if (m_isPost) 104 | m_context.Writer.Append(string.Format("{0}{1}", variable, m_shortType)); 105 | else 106 | m_context.Writer.Append(string.Format("{1}{0}", variable, m_shortType)); 107 | } 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /LibCS2C/Generators/PropertyGenerator.cs: -------------------------------------------------------------------------------- 1 | using LibCS2C.Context; 2 | using Microsoft.CodeAnalysis; 3 | using Microsoft.CodeAnalysis.CSharp; 4 | using Microsoft.CodeAnalysis.CSharp.Syntax; 5 | using System; 6 | using System.Linq; 7 | 8 | namespace LibCS2C.Generators 9 | { 10 | public class PropertyGenerator : GeneratorBase 11 | { 12 | /// 13 | /// Property generator 14 | /// 15 | /// The walker context 16 | public PropertyGenerator(WalkerContext context) 17 | { 18 | m_context = context; 19 | } 20 | 21 | /// 22 | /// Generate code for property declaration 23 | /// 24 | /// 25 | public override void Generate(PropertyDeclarationSyntax node) 26 | { 27 | ChildSyntaxList children = node.ChildNodesAndTokens(); 28 | SyntaxNode parentNode = node.Parent; 29 | SyntaxKind parentKind = parentNode.Kind(); 30 | 31 | bool isStatic = false; 32 | foreach (SyntaxNodeOrToken child in children) 33 | { 34 | SyntaxKind childKind = child.Kind(); 35 | 36 | if (childKind == SyntaxKind.StaticKeyword) 37 | { 38 | isStatic = true; 39 | } 40 | else if (childKind == SyntaxKind.AccessorList) 41 | { 42 | // Determine where the property is located and use that to determine the names 43 | string objTypeName, typeName; 44 | if (parentKind == SyntaxKind.StructDeclaration) 45 | { 46 | StructDeclarationSyntax structDeclaration = parentNode as StructDeclarationSyntax; 47 | typeName = m_context.TypeConvert.ConvertClassName(structDeclaration.Identifier.ToString()); 48 | objTypeName = "struct struct_" + m_context.TypeConvert.ConvertClassName(structDeclaration.Identifier.ToString()); 49 | } 50 | else if (parentKind == SyntaxKind.ClassDeclaration) 51 | { 52 | typeName = m_context.TypeConvert.CurrentClassNameFormatted; 53 | objTypeName = m_context.TypeConvert.CurrentClassStructName; 54 | } 55 | else if (parentKind == SyntaxKind.InterfaceDeclaration) 56 | { 57 | InterfaceDeclarationSyntax interfaceDeclaration = parentNode as InterfaceDeclarationSyntax; 58 | typeName = m_context.TypeConvert.ConvertClassName(interfaceDeclaration.Identifier.ToString()); 59 | objTypeName = "struct " + m_context.TypeConvert.ConvertClassName(interfaceDeclaration.Identifier.ToString()); 60 | } 61 | else 62 | { 63 | throw new NotImplementedException("Unknown parent for getter: " + parentKind); 64 | } 65 | 66 | AccessorListSyntax accessors = child.AsNode() as AccessorListSyntax; 67 | SyntaxList accessorDeclarations = accessors.Accessors; 68 | 69 | AccessorDeclarationSyntax getAccessor = (from a in accessorDeclarations 70 | where a.Kind() == SyntaxKind.GetAccessorDeclaration 71 | select a).FirstOrDefault(); 72 | 73 | AccessorDeclarationSyntax setAccessor = (from a in accessorDeclarations 74 | where a.Kind() == SyntaxKind.SetAccessorDeclaration 75 | select a).FirstOrDefault(); 76 | 77 | // Method/macro names 78 | string commonName = typeName + "_" + node.Identifier; 79 | string getterName = commonName + "_getter"; 80 | string setterName = commonName + "_setter"; 81 | 82 | if (getAccessor != default(AccessorDeclarationSyntax)) 83 | { 84 | // No custom body for getter, just return the variable 85 | if (getAccessor.Body == null) 86 | { 87 | m_context.Writer.CurrentDestination = WriterDestination.MethodPrototypes; 88 | 89 | if (isStatic) 90 | m_context.Writer.AppendLine(string.Format("#define {0}() (classStatics_{1}.prop_{2})", getterName, typeName, node.Identifier)); 91 | else 92 | m_context.Writer.AppendLine(string.Format("#define {0}(obj) ((({1}*)obj)->prop_{2})", getterName, objTypeName, node.Identifier)); 93 | } 94 | // Custom body for getter, method required 95 | else 96 | { 97 | string methodPrototype; 98 | if (isStatic) 99 | methodPrototype = string.Format("{0} {1}(void)", m_context.ConvertTypeName(node.Type), getterName); 100 | else 101 | methodPrototype = string.Format("{0} {1}({2}* obj)", m_context.ConvertTypeName(node.Type), getterName, objTypeName); 102 | 103 | // Method prototype 104 | m_context.Writer.CurrentDestination = WriterDestination.MethodPrototypes; 105 | m_context.Writer.Append(methodPrototype); 106 | m_context.Writer.AppendLine(";"); 107 | 108 | // Method declaration 109 | m_context.Writer.CurrentDestination = WriterDestination.MethodDeclarations; 110 | m_context.Writer.AppendLine(methodPrototype); 111 | m_context.Writer.AppendLine("{"); 112 | m_context.Generators.Block.Generate(getAccessor.Body); 113 | m_context.Writer.AppendLine("}"); 114 | } 115 | } 116 | 117 | if (setAccessor != default(AccessorDeclarationSyntax)) 118 | { 119 | // No custom body for setter, just set the variable 120 | if (setAccessor.Body == null) 121 | { 122 | m_context.Writer.CurrentDestination = WriterDestination.MethodPrototypes; 123 | 124 | if (isStatic) 125 | m_context.Writer.AppendLine(string.Format("#define {0}(value) (classStatics_{1}.prop_{2} = ({3})value)", setterName, typeName, node.Identifier, m_context.ConvertTypeName(node.Type))); 126 | else 127 | m_context.Writer.AppendLine(string.Format("#define {0}(obj, value) ((({1}*)obj)->prop_{2} = ({3})value)", setterName, objTypeName, node.Identifier, m_context.ConvertTypeName(node.Type))); 128 | } 129 | // Custom body for setter, method required 130 | else 131 | { 132 | string methodPrototype; 133 | if (isStatic) 134 | methodPrototype = string.Format("{0} {1}({0} value)", m_context.ConvertTypeName(node.Type), setterName); 135 | else 136 | methodPrototype = string.Format("{0} {1}({2}* obj, {0} value)", m_context.ConvertTypeName(node.Type), setterName, objTypeName); 137 | 138 | // Method prototype 139 | m_context.Writer.CurrentDestination = WriterDestination.MethodPrototypes; 140 | m_context.Writer.Append(methodPrototype); 141 | m_context.Writer.AppendLine(";"); 142 | 143 | // Method declaration 144 | m_context.Writer.CurrentDestination = WriterDestination.MethodDeclarations; 145 | m_context.Writer.AppendLine(methodPrototype); 146 | m_context.Writer.AppendLine("{"); 147 | 148 | if (setAccessor.Body == null) 149 | { 150 | if (isStatic) 151 | m_context.Writer.AppendLine(string.Format("\tclassStatics_{0}.prop_{1} = value;", typeName, node.Identifier)); 152 | else 153 | m_context.Writer.AppendLine(string.Format("\tobj->prop_{0} = value;", node.Identifier)); 154 | } 155 | else 156 | { 157 | m_context.Generators.Block.Generate(setAccessor.Body); 158 | } 159 | 160 | m_context.Writer.AppendLine("\treturn value;"); 161 | m_context.Writer.AppendLine("}"); 162 | } 163 | } 164 | } 165 | } 166 | } 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /LibCS2C/Generators/ReturnStatementGenerator.cs: -------------------------------------------------------------------------------- 1 | using LibCS2C.Context; 2 | using Microsoft.CodeAnalysis; 3 | using Microsoft.CodeAnalysis.CSharp.Syntax; 4 | 5 | namespace LibCS2C.Generators 6 | { 7 | public class ReturnStatementGenerator : GeneratorBase 8 | { 9 | /// 10 | /// Return statement generator 11 | /// 12 | /// The walker context 13 | public ReturnStatementGenerator(WalkerContext context) 14 | { 15 | m_context = context; 16 | } 17 | 18 | /// 19 | /// Generates the return statement code 20 | /// 21 | /// The return statement 22 | public override void Generate(ReturnStatementSyntax node) 23 | { 24 | m_context.Writer.Append("return "); 25 | 26 | if (node.Expression != null) 27 | { 28 | ITypeSymbol type = m_context.Model.GetTypeInfo(node.Expression).Type; 29 | if (type != null && !m_context.GenericTypeConvert.IsGeneric(type) && type.TypeKind == TypeKind.Class) 30 | m_context.Writer.Append("(void*)"); 31 | 32 | m_context.Generators.Expression.Generate(node.Expression); 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /LibCS2C/Generators/SimpleAssignmentGenerator.cs: -------------------------------------------------------------------------------- 1 | using LibCS2C.Context; 2 | using Microsoft.CodeAnalysis; 3 | using Microsoft.CodeAnalysis.CSharp; 4 | using Microsoft.CodeAnalysis.CSharp.Syntax; 5 | using System.Linq; 6 | 7 | namespace LibCS2C.Generators 8 | { 9 | public class SimpleAssignmentGenerator : GeneratorBase 10 | { 11 | /// 12 | /// Simple assignment generator 13 | /// 14 | /// The walker context 15 | public SimpleAssignmentGenerator(WalkerContext context) 16 | { 17 | m_context = context; 18 | } 19 | 20 | /// 21 | /// Generates a simple assignment 22 | /// 23 | /// The expression node 24 | public override void Generate(AssignmentExpressionSyntax node) 25 | { 26 | // The first node will be an identifier 27 | // Check its type, if it's a property, that means we need to use the setter 28 | ISymbol symbol = m_context.Model.GetSymbolInfo(node.ChildNodes().First()).Symbol; 29 | bool isProperty = (symbol != null && symbol.Kind == SymbolKind.Property); 30 | 31 | if (isProperty) 32 | { 33 | // If the first node is a memberaccess, we need to get the object name from that node 34 | string objName = "obj"; 35 | string prefix = ""; 36 | 37 | ChildSyntaxList expression = (node as ExpressionSyntax).ChildNodesAndTokens(); 38 | SyntaxNode firstNode = expression[0].AsNode(); 39 | 40 | if (firstNode is MemberAccessExpressionSyntax) 41 | { 42 | SyntaxNode firstChild = firstNode.ChildNodes().First(); 43 | SyntaxKind firstChildKind = firstChild.Kind(); 44 | 45 | // Check if the argument needs to be passed as a reference 46 | ITypeSymbol childTypeSymbol = m_context.Model.GetTypeInfo(firstChild).Type; 47 | if (!m_context.GenericTypeConvert.IsGeneric(childTypeSymbol) && childTypeSymbol.TypeKind == TypeKind.Struct) 48 | { 49 | prefix = "&"; 50 | } 51 | 52 | WriterDestination destination = m_context.Writer.CurrentDestination; 53 | m_context.Writer.CurrentDestination = WriterDestination.TempBuffer; 54 | m_context.Generators.Expression.Generate(firstChild as ExpressionSyntax); 55 | m_context.Writer.CurrentDestination = destination; 56 | objName = m_context.Writer.FlushTempBuffer(); 57 | } 58 | 59 | m_context.Writer.Append(string.Format("{0}_{1}_setter({2}", symbol.ContainingType.ToString().Replace(".", "_"), symbol.Name, prefix)); 60 | if (!symbol.IsStatic) 61 | m_context.Writer.Append(string.Format("{0},", objName)); 62 | } 63 | else 64 | { 65 | m_context.Generators.Expression.Generate(node.Left); 66 | m_context.Writer.Append("="); 67 | } 68 | 69 | // If the type on the right is an object, cast it 70 | ITypeSymbol leftSymbol = m_context.Model.GetTypeInfo(node.Left).Type; 71 | ITypeSymbol rightSymbol = m_context.Model.GetTypeInfo(node.Right).Type; 72 | if (leftSymbol != null && rightSymbol != null && !leftSymbol.Name.Equals(rightSymbol.Name) && rightSymbol.TypeKind == TypeKind.Class && !m_context.GenericTypeConvert.IsGeneric(rightSymbol)) 73 | m_context.Writer.Append("(void*)"); 74 | 75 | m_context.Generators.Expression.Generate(node.Right); 76 | 77 | if (isProperty) 78 | m_context.Writer.Append(")"); 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /LibCS2C/Generators/SimpleMemberAccessGenerator.cs: -------------------------------------------------------------------------------- 1 | using LibCS2C.Context; 2 | using Microsoft.CodeAnalysis; 3 | using Microsoft.CodeAnalysis.CSharp; 4 | using Microsoft.CodeAnalysis.CSharp.Syntax; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | 8 | namespace LibCS2C.Generators 9 | { 10 | public class SimpleMemberAccessGenerator : GeneratorBase 11 | { 12 | /// 13 | /// Member access generator generator 14 | /// 15 | /// The walker context 16 | /// The method type: constructor or method 17 | public SimpleMemberAccessGenerator(WalkerContext context) 18 | { 19 | m_context = context; 20 | } 21 | 22 | /// 23 | /// Generates the object part 24 | /// 25 | /// The object node 26 | /// If the identifier should be parsed as an expression (for object part) 27 | private void GenerateObjectPart(SyntaxNode node, bool identifierAsExpression) 28 | { 29 | SyntaxKind firstKind = node.Kind(); 30 | 31 | if (firstKind == SyntaxKind.ThisExpression) 32 | { 33 | m_context.Writer.Append("obj"); 34 | } 35 | else if (firstKind == SyntaxKind.IdentifierName) 36 | { 37 | if (identifierAsExpression) 38 | m_context.Generators.Expression.Generate(node); 39 | else 40 | m_context.Writer.Append(m_context.TypeConvert.ConvertVariableName(node)); 41 | } 42 | else 43 | { 44 | m_context.Generators.Expression.Generate(node); 45 | } 46 | } 47 | 48 | /// 49 | /// Generates a member access 50 | /// 51 | /// The expression of the member access 52 | public override void Generate(ExpressionSyntax node) 53 | { 54 | ITypeSymbol symbolType = m_context.Model.GetTypeInfo(node).Type; 55 | ISymbol nodeSymbol = m_context.Model.GetSymbolInfo(node).Symbol; 56 | SyntaxNodeOrToken[] children = node.ChildNodesAndTokens().ToArray(); 57 | 58 | // Check if it's a constant-defined value 59 | bool isDefined = (symbolType != null && symbolType.TypeKind == TypeKind.Enum); 60 | bool isConst = false; 61 | 62 | if (nodeSymbol.DeclaringSyntaxReferences.Length > 0) 63 | { 64 | SyntaxNode declaration = nodeSymbol.DeclaringSyntaxReferences[0].GetSyntax().Parent; 65 | if (declaration.Kind() == SyntaxKind.VariableDeclaration) 66 | { 67 | IEnumerable fieldNodeTokens = declaration.Parent.ChildTokens(); 68 | foreach (SyntaxToken token in fieldNodeTokens) 69 | { 70 | if (token.Kind() == SyntaxKind.ConstKeyword) 71 | { 72 | isDefined = true; 73 | isConst = true; 74 | break; 75 | } 76 | } 77 | } 78 | } 79 | 80 | // After the type is checked as enum, check if it is an assignment to a enum type 81 | // if so, we cannot transform this to a constant 82 | if (isDefined) 83 | { 84 | SyntaxNode parent = node.Parent; 85 | 86 | string sType = symbolType.ToString(); 87 | sType = sType.Substring(sType.LastIndexOf('.') + 1); 88 | 89 | string checkType = nodeSymbol.ToString(); 90 | checkType = checkType.Substring(0, checkType.LastIndexOf('.')); 91 | checkType = checkType.Substring(checkType.LastIndexOf('.') + 1); 92 | 93 | if (sType != checkType) 94 | { 95 | if (nodeSymbol.Kind == SymbolKind.Field || nodeSymbol.Kind == SymbolKind.Local) 96 | { 97 | // Check if the right hand of the expression isn't equal to this node, then we know it comes from the left 98 | // and should be a variable instead of an enum 99 | if (parent.ChildNodes().Count() > 1 && node != parent.ChildNodes().ElementAt(1)) 100 | { 101 | isDefined = false; 102 | } 103 | } 104 | } 105 | 106 | // If the symbol is a class and the child is a field and the field is non-static, it can't be a defined constant 107 | if (isDefined && !isConst && children[0].Kind() == SyntaxKind.IdentifierName) 108 | { 109 | IdentifierNameSyntax name = children[0].AsNode() as IdentifierNameSyntax; 110 | IdentifierNameSyntax field = children[2].AsNode() as IdentifierNameSyntax; 111 | 112 | SymbolKind kind = m_context.Model.GetSymbolInfo(field).Symbol.Kind; 113 | if (m_context.Model.GetTypeInfo(name).Type.TypeKind == TypeKind.Class && (kind == SymbolKind.Field || kind == SymbolKind.Property) && !m_context.Model.GetTypeInfo(field).Type.IsStatic) 114 | isDefined = false; 115 | } 116 | } 117 | 118 | // Enum 119 | if (isDefined) 120 | { 121 | IdentifierNameSyntax name = children[2].AsNode() as IdentifierNameSyntax; 122 | string prefix = (isConst) ? "const" : "enum"; 123 | string containing = (isConst) ? nodeSymbol.ContainingType.ToString() : symbolType.ToString(); 124 | m_context.Writer.Append(string.Format("{0}_{1}_{2}", prefix, containing.Replace(".", "_"), name.Identifier)); 125 | } 126 | // Normal member access 127 | else 128 | { 129 | // If it's static, we don't need the first part (identifier) 130 | // because the reference is already in the second part (identifier) 131 | SyntaxNode first = children[0].AsNode(); 132 | ISymbol symbol = m_context.Model.GetSymbolInfo(node).Symbol; 133 | ISymbol firstSymbol = m_context.Model.GetSymbolInfo(first).Symbol; 134 | 135 | // Object part that contains the requested variable 136 | bool objectFirst = (!symbol.IsStatic && symbol.Kind != SymbolKind.Property); 137 | if (objectFirst) 138 | { 139 | GenerateObjectPart(first, true); 140 | 141 | ITypeSymbol type = m_context.Model.GetTypeInfo(first).Type; 142 | if (type.TypeKind == TypeKind.Struct) 143 | m_context.Writer.Append("."); 144 | else 145 | m_context.Writer.Append("->"); 146 | } 147 | 148 | // Variable name 149 | SyntaxNode name = children[2].AsNode(); 150 | bool getterArgument = (symbol.Kind == SymbolKind.Property && !symbol.IsStatic); 151 | string convertedVariableName = m_context.TypeConvert.ConvertVariableName(name); 152 | 153 | // Property getter argument 154 | if (getterArgument) 155 | { 156 | // Make sure there are no double arguments 157 | int indexOfArg = convertedVariableName.IndexOf("("); 158 | if (indexOfArg > -1) 159 | convertedVariableName = convertedVariableName.Substring(0, indexOfArg); 160 | 161 | m_context.Writer.Append(convertedVariableName); 162 | m_context.Writer.Append("("); 163 | 164 | ITypeSymbol typeSymbol = m_context.Model.GetTypeInfo(first).Type; 165 | 166 | // Pass struct in this case by reference 167 | // Note: we need to surround the object part with extra parantheses in case it is a getter 168 | bool makePointer = (!m_context.GenericTypeConvert.IsGeneric(typeSymbol) && typeSymbol.TypeKind == TypeKind.Struct); 169 | if (makePointer) 170 | m_context.Writer.Append("&"); 171 | 172 | if (firstSymbol != null && (!firstSymbol.IsStatic && firstSymbol.Kind == SymbolKind.Field)) 173 | m_context.Writer.Append("obj->"); 174 | 175 | if (makePointer) 176 | m_context.Writer.Append("("); 177 | 178 | GenerateObjectPart(first, false); 179 | 180 | if (makePointer) 181 | m_context.Writer.Append("))"); 182 | else 183 | m_context.Writer.Append(")"); 184 | } 185 | else 186 | { 187 | m_context.Writer.Append(convertedVariableName); 188 | } 189 | } 190 | } 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /LibCS2C/Generators/SizeofExpressionGenerator.cs: -------------------------------------------------------------------------------- 1 | using LibCS2C.Context; 2 | using Microsoft.CodeAnalysis.CSharp.Syntax; 3 | 4 | namespace LibCS2C.Generators 5 | { 6 | public class SizeofExpressionGenerator : GeneratorBase 7 | { 8 | /// 9 | /// Sizeof statement generator 10 | /// 11 | /// The walker context 12 | public SizeofExpressionGenerator(WalkerContext context) 13 | { 14 | m_context = context; 15 | } 16 | 17 | /// 18 | /// Generates a sizeof expression 19 | /// 20 | /// The sizeof expression 21 | public override void Generate(SizeOfExpressionSyntax node) 22 | { 23 | m_context.Writer.Append(string.Format("sizeof({0})", m_context.ConvertTypeName(node.Type))); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /LibCS2C/Generators/StructGenerator.cs: -------------------------------------------------------------------------------- 1 | using LibCS2C.Context; 2 | using Microsoft.CodeAnalysis; 3 | using Microsoft.CodeAnalysis.CSharp; 4 | using Microsoft.CodeAnalysis.CSharp.Syntax; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | 9 | namespace LibCS2C.Generators 10 | { 11 | public class StructGenerator : GeneratorBase 12 | { 13 | /// 14 | /// struct generator 15 | /// 16 | /// The walker context 17 | public StructGenerator(WalkerContext context) 18 | { 19 | m_context = context; 20 | } 21 | 22 | /// 23 | /// Generates a struct declaration 24 | /// 25 | /// The struct declaration 26 | public override void Generate(StructDeclarationSyntax node) 27 | { 28 | WriterDestination destination = m_context.Writer.CurrentDestination; 29 | 30 | // Check for attributes 31 | bool packed = false; 32 | 33 | SyntaxList attribLists = node.AttributeLists; 34 | foreach (AttributeListSyntax attribList in attribLists) 35 | { 36 | SeparatedSyntaxList attribs = attribList.Attributes; 37 | foreach (AttributeSyntax attrib in attribs) 38 | { 39 | IdentifierNameSyntax name = attrib.ChildNodes().First() as IdentifierNameSyntax; 40 | string identifier = name.Identifier.ToString(); 41 | 42 | // Defines layout of the struct 43 | if (identifier.Equals("StructLayoutAttribute") || identifier.Equals("StructLayout")) 44 | { 45 | SeparatedSyntaxList argsList = attrib.ArgumentList.Arguments; 46 | foreach (AttributeArgumentSyntax arg in argsList) 47 | { 48 | SyntaxNode first = arg.ChildNodes().First(); 49 | SyntaxKind kind = first.Kind(); 50 | 51 | if (kind == SyntaxKind.NameEquals) 52 | { 53 | NameEqualsSyntax nameEquals = first as NameEqualsSyntax; 54 | string nameIdentifier = nameEquals.Name.Identifier.ToString(); 55 | 56 | if (nameIdentifier.Equals("Pack")) 57 | { 58 | packed = true; 59 | } 60 | } 61 | } 62 | } 63 | // Unknown attribute 64 | else 65 | { 66 | throw new NotImplementedException("Unknown attribute on struct: " + identifier); 67 | } 68 | } 69 | } 70 | 71 | // Create struct name 72 | string structName; 73 | if (node.Parent is ClassDeclarationSyntax) 74 | { 75 | structName = string.Format("{0}_{1}", m_context.TypeConvert.CurrentClassNameFormatted, node.Identifier.ToString()); 76 | } 77 | else 78 | { 79 | structName = string.Format("{0}_{1}", m_context.TypeConvert.CurrentNamespaceFormatted, node.Identifier.ToString()); 80 | } 81 | 82 | // Temporarily hold all the data 83 | Dictionary dataTypes = new Dictionary(); 84 | Dictionary dataSuffixes = new Dictionary(); 85 | 86 | // Collect the data and put it in the dictionaries 87 | IEnumerable children = node.ChildNodes(); 88 | foreach (SyntaxNode child in children) 89 | { 90 | SyntaxKind kind = child.Kind(); 91 | 92 | if (kind == SyntaxKind.FieldDeclaration) 93 | { 94 | FieldDeclarationSyntax field = child as FieldDeclarationSyntax; 95 | IEnumerable fieldChildren = field.ChildNodes(); 96 | 97 | foreach (VariableDeclarationSyntax fieldChild in fieldChildren) 98 | { 99 | foreach (VariableDeclaratorSyntax variable in fieldChild.Variables) 100 | { 101 | string identifier = "field_" + variable.Identifier.ToString(); 102 | dataTypes.Add(identifier, fieldChild.Type); 103 | 104 | BracketedArgumentListSyntax argumentList = (from a in variable.ChildNodes() 105 | where a.Kind() == SyntaxKind.BracketedArgumentList 106 | select a).FirstOrDefault() as BracketedArgumentListSyntax; 107 | 108 | if (argumentList != default(BracketedArgumentListSyntax)) 109 | { 110 | ArgumentSyntax argument = argumentList.Arguments[0]; 111 | WriterDestination dest = m_context.Writer.CurrentDestination; 112 | m_context.Writer.CurrentDestination = WriterDestination.TempBuffer; 113 | m_context.Generators.ArgumentList.GenerateArgument(argument); 114 | string arg = m_context.Writer.FlushTempBuffer(); 115 | dataSuffixes.Add(identifier, "[" + arg + "]"); 116 | m_context.Writer.CurrentDestination = dest; 117 | } 118 | } 119 | } 120 | } 121 | else if (kind == SyntaxKind.PropertyDeclaration) 122 | { 123 | PropertyDeclarationSyntax property = child as PropertyDeclarationSyntax; 124 | string identifier = "prop_" + property.Identifier.ToString(); 125 | dataTypes.Add(identifier, property.Type); 126 | } 127 | } 128 | 129 | // Struct prototype 130 | string structPrototype = string.Format("struct struct_{0}", structName); 131 | m_context.Writer.CurrentDestination = WriterDestination.StructPrototypes; 132 | m_context.Writer.AppendLine(string.Format("{0};", structPrototype)); 133 | 134 | // Struct definition 135 | m_context.Writer.CurrentDestination = WriterDestination.Structs; 136 | m_context.Writer.AppendLine(structPrototype); 137 | m_context.Writer.AppendLine("{"); 138 | 139 | foreach (KeyValuePair pair in dataTypes) 140 | { 141 | m_context.Writer.Append(string.Format("\t{0} {1}", m_context.ConvertTypeName(pair.Value), pair.Key)); 142 | if (dataSuffixes.ContainsKey(pair.Key)) 143 | m_context.Writer.Append(dataSuffixes[pair.Key]); 144 | m_context.Writer.AppendLine(";"); 145 | } 146 | 147 | // Attributes 148 | if (packed) 149 | m_context.Writer.AppendLine("} __attribute__((packed));"); 150 | else 151 | m_context.Writer.AppendLine("};"); 152 | 153 | 154 | // Method prototype of init code 155 | string methodName = string.Format("struct struct_{0} structInit_{0}(void)", structName); 156 | m_context.Writer.CurrentDestination = WriterDestination.MethodPrototypes; 157 | m_context.Writer.Append("extern " + methodName); 158 | m_context.Writer.AppendLine(";"); 159 | 160 | // Init method declaration 161 | m_context.Writer.CurrentDestination = WriterDestination.MethodDeclarations; 162 | m_context.Writer.AppendLine("inline " + methodName); 163 | m_context.Writer.AppendLine("{"); 164 | string structType = "struct struct_" + structName; 165 | m_context.Writer.AppendLine(string.Format("\t{0} object;", structType)); 166 | m_context.Writer.AppendLine(string.Format("\tmemset(&object, 0, sizeof({0}));", structType)); 167 | m_context.Writer.AppendLine("\treturn object;"); 168 | m_context.Writer.AppendLine("}"); 169 | 170 | m_context.Writer.CurrentDestination = destination; 171 | } 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /LibCS2C/Generators/SwitchStatementGenerator.cs: -------------------------------------------------------------------------------- 1 | using LibCS2C.Context; 2 | using Microsoft.CodeAnalysis; 3 | using Microsoft.CodeAnalysis.CSharp; 4 | using Microsoft.CodeAnalysis.CSharp.Syntax; 5 | using System; 6 | 7 | namespace LibCS2C.Generators 8 | { 9 | public class SwitchStatementGenerator : GeneratorBase 10 | { 11 | /// 12 | /// Switch generator 13 | /// 14 | /// The walker context 15 | public SwitchStatementGenerator(WalkerContext context) 16 | { 17 | m_context = context; 18 | } 19 | 20 | /// 21 | /// Generates a switch 22 | /// 23 | /// The switch 24 | public override void Generate(SwitchStatementSyntax node) 25 | { 26 | m_context.Writer.Append("switch("); 27 | m_context.Generators.Expression.Generate(node.Expression); 28 | m_context.Writer.AppendLine(")"); 29 | m_context.Writer.AppendLine("{"); 30 | m_context.Writer.Indent(); 31 | 32 | SyntaxList sections = node.Sections; 33 | foreach (SwitchSectionSyntax section in sections) 34 | { 35 | // Labels for this section 36 | SyntaxList labels = section.Labels; 37 | foreach (SwitchLabelSyntax label in labels) 38 | { 39 | SyntaxKind labelKind = label.Kind(); 40 | if (labelKind == SyntaxKind.CaseSwitchLabel) 41 | { 42 | CaseSwitchLabelSyntax caseLabel = label as CaseSwitchLabelSyntax; 43 | m_context.Writer.Append("case ("); 44 | m_context.Generators.Expression.Generate(caseLabel.Value); 45 | m_context.Writer.AppendLine("):"); 46 | } 47 | else /* if(labelKind == SyntaxKind.DefaultSwitchLabel) */ 48 | { 49 | m_context.Writer.AppendLine("default:"); 50 | } 51 | } 52 | 53 | m_context.Writer.AppendLine("{"); 54 | 55 | m_context.Writer.Indent(); 56 | 57 | // Statement for this section 58 | SyntaxList statements = section.Statements; 59 | foreach (StatementSyntax statement in statements) 60 | { 61 | SyntaxKind kind = statement.Kind(); 62 | 63 | if (kind == SyntaxKind.Block) 64 | { 65 | m_context.Writer.AppendLine("{"); 66 | m_context.Generators.Block.Generate(statement as BlockSyntax); 67 | m_context.Writer.AppendLine("}"); 68 | } 69 | else if (m_context.Generators.Expression.IsSubExpression(kind)) 70 | { 71 | m_context.Generators.Expression.Generate(statement as ExpressionStatementSyntax); 72 | m_context.Writer.AppendLine(""); 73 | } 74 | else 75 | { 76 | m_context.Generators.Block.GenerateChild(statement); 77 | } 78 | } 79 | 80 | m_context.Writer.AppendLine("}"); 81 | 82 | m_context.Writer.UnIndent(); 83 | } 84 | 85 | m_context.Writer.UnIndent(); 86 | m_context.Writer.AppendLine("}"); 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /LibCS2C/Generators/UncheckedStatementGenerator.cs: -------------------------------------------------------------------------------- 1 | using LibCS2C.Context; 2 | using Microsoft.CodeAnalysis.CSharp.Syntax; 3 | 4 | namespace LibCS2C.Generators 5 | { 6 | public class checkedStatementGenerator : GeneratorBase 7 | { 8 | /// 9 | /// Checked statement generator 10 | /// 11 | /// The walker context 12 | public checkedStatementGenerator(WalkerContext context) 13 | { 14 | m_context = context; 15 | } 16 | 17 | /// 18 | /// Generates an checked statement 19 | /// 20 | /// The statement 21 | public override void Generate(CheckedStatementSyntax node) 22 | { 23 | m_context.Generators.Block.Generate(node.Block); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /LibCS2C/Generators/VariableGenerator.cs: -------------------------------------------------------------------------------- 1 | using LibCS2C.Context; 2 | using Microsoft.CodeAnalysis.CSharp.Syntax; 3 | 4 | namespace LibCS2C.Generators 5 | { 6 | public class VariableGenerator : GeneratorBase 7 | { 8 | /// 9 | /// Variable declaration generator 10 | /// 11 | /// The walker context 12 | public VariableGenerator(WalkerContext context) 13 | { 14 | m_context = context; 15 | } 16 | 17 | /// 18 | /// Generate code for variable declaration 19 | /// 20 | /// 21 | public override void Generate(VariableDeclarationSyntax node) 22 | { 23 | m_context.Writer.Append(m_context.ConvertTypeName(node.Type)); 24 | m_context.Writer.Append(" "); 25 | 26 | int varCount = node.Variables.Count; 27 | int i = 0; 28 | foreach (VariableDeclaratorSyntax variable in node.Variables) 29 | { 30 | m_context.Writer.Append(variable.Identifier.ToString()); 31 | 32 | // Initial value 33 | if (variable.Initializer != null) 34 | { 35 | m_context.Writer.Append(" = "); 36 | ExpressionSyntax expression = variable.Initializer.Value; 37 | m_context.Generators.Expression.Generate(expression); 38 | } 39 | 40 | // There can be more than one variable 41 | if (i != varCount - 1) 42 | m_context.Writer.Append(", "); 43 | 44 | i++; 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /LibCS2C/Generators/WhileStatementGenerator.cs: -------------------------------------------------------------------------------- 1 | using LibCS2C.Context; 2 | using Microsoft.CodeAnalysis.CSharp.Syntax; 3 | 4 | namespace LibCS2C.Generators 5 | { 6 | public class WhileStatementGenerator : GeneratorBase 7 | { 8 | /// 9 | /// While statement generator 10 | /// 11 | /// The walker context 12 | public WhileStatementGenerator(WalkerContext context) 13 | { 14 | m_context = context; 15 | } 16 | 17 | /// 18 | /// Generates a while statement 19 | /// 20 | /// The while statement 21 | public override void Generate(WhileStatementSyntax node) 22 | { 23 | m_context.Writer.Append("while("); 24 | m_context.Generators.Expression.Generate(node.Condition); 25 | m_context.Writer.AppendLine(")"); 26 | 27 | // Code inside the loop 28 | if (node.Statement != null) 29 | { 30 | m_context.Writer.AppendLine("{"); 31 | m_context.Writer.Indent(); 32 | m_context.Generators.Block.GenerateChild(node.Statement); 33 | m_context.Writer.UnIndent(); 34 | m_context.Writer.AppendLine("}"); 35 | } 36 | else 37 | { 38 | m_context.Writer.AppendLine(";"); 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /LibCS2C/LibCS2C.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {12C65AF1-DF61-4105-AD57-8369A928D2E1} 8 | Library 9 | Properties 10 | LibCS2C 11 | LibCS2C 12 | v4.5.2 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | pdbonly 26 | true 27 | bin\Release\ 28 | TRACE 29 | prompt 30 | 4 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | ..\packages\Microsoft.CodeAnalysis.Common.1.2.2\lib\net45\Microsoft.CodeAnalysis.dll 39 | True 40 | 41 | 42 | ..\packages\Microsoft.CodeAnalysis.CSharp.1.2.2\lib\net45\Microsoft.CodeAnalysis.CSharp.dll 43 | True 44 | 45 | 46 | ..\packages\Microsoft.CodeAnalysis.CSharp.Workspaces.1.2.2\lib\net45\Microsoft.CodeAnalysis.CSharp.Workspaces.dll 47 | True 48 | 49 | 50 | ..\packages\Microsoft.CodeAnalysis.VisualBasic.1.2.2\lib\net45\Microsoft.CodeAnalysis.VisualBasic.dll 51 | True 52 | 53 | 54 | ..\packages\Microsoft.CodeAnalysis.VisualBasic.Workspaces.1.2.2\lib\net45\Microsoft.CodeAnalysis.VisualBasic.Workspaces.dll 55 | True 56 | 57 | 58 | ..\packages\Microsoft.CodeAnalysis.Workspaces.Common.1.2.2\lib\net45\Microsoft.CodeAnalysis.Workspaces.dll 59 | True 60 | 61 | 62 | ..\packages\Microsoft.CodeAnalysis.Workspaces.Common.1.2.2\lib\net45\Microsoft.CodeAnalysis.Workspaces.Desktop.dll 63 | True 64 | 65 | 66 | 67 | ..\packages\System.Collections.Immutable.1.1.37\lib\dotnet\System.Collections.Immutable.dll 68 | True 69 | 70 | 71 | ..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.AttributedModel.dll 72 | True 73 | 74 | 75 | ..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.Convention.dll 76 | True 77 | 78 | 79 | ..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.Hosting.dll 80 | True 81 | 82 | 83 | ..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.Runtime.dll 84 | True 85 | 86 | 87 | ..\packages\Microsoft.Composition.1.0.27\lib\portable-net45+win8+wp8+wpa81\System.Composition.TypedParts.dll 88 | True 89 | 90 | 91 | 92 | ..\packages\System.Reflection.Metadata.1.2.0\lib\portable-net45+win8\System.Reflection.Metadata.dll 93 | True 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 179 | -------------------------------------------------------------------------------- /LibCS2C/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("LibCS2C")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("LibCS2C")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("12c65af1-df61-4105-ad57-8369a928d2e1")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /LibCS2C/Tasks/CompileProjectTask.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Build.Framework; 2 | using Microsoft.Build.Utilities; 3 | using System; 4 | using System.Diagnostics; 5 | using LibCS2C.Compilation; 6 | using System.IO; 7 | 8 | namespace LibCS2C.Tasks 9 | { 10 | public class CompileProjectTask : Task 11 | { 12 | [Required] 13 | public string Path { get; private set; } 14 | 15 | [Required] 16 | public string SourceOutPath { get; private set; } 17 | 18 | [Required] 19 | public string HeaderOutPath { get; private set; } 20 | 21 | public string AfterBuildCommand { get; private set; } 22 | public string AfterBuildWorkingDir { get; private set; } 23 | public string HeaderFiles { get; private set; } 24 | public string InitSuffix { get; private set; } 25 | 26 | /// 27 | /// Executes the compiler 28 | /// 29 | /// If the compilation was successful 30 | public override bool Execute() 31 | { 32 | // Log a high-importance comment 33 | Log.LogMessage(MessageImportance.High, "CS2C Compiler: Compiling project \"" + Path + "\"."); 34 | 35 | // Header files 36 | string[] headers = new string[0]; 37 | if (HeaderFiles != null) 38 | headers = HeaderFiles.Split(' '); 39 | 40 | Compiler compiler = new Compiler(); 41 | try 42 | { 43 | compiler.CompileProject(Path, (InitSuffix == null) ? "" : InitSuffix); 44 | compiler.CreateHeaderFile(HeaderOutPath, headers); 45 | compiler.CreateSourceFile(SourceOutPath, new string[] { Directory.GetCurrentDirectory() + "/" + HeaderOutPath }); 46 | 47 | // Command after building is done 48 | if (AfterBuildCommand != null) 49 | { 50 | Log.LogMessage(MessageImportance.High, "Running command after build: " + AfterBuildCommand); 51 | 52 | ProcessStartInfo info = new ProcessStartInfo(AfterBuildCommand); 53 | if (AfterBuildWorkingDir != null) 54 | info.WorkingDirectory = AfterBuildWorkingDir; 55 | 56 | Process.Start(info); 57 | } 58 | 59 | Log.LogMessage(MessageImportance.High, "Finished compiling"); 60 | } 61 | catch (Exception e) 62 | { 63 | Log.LogErrorFromException(e); 64 | Log.LogError("StackTrace: " + e.StackTrace); 65 | Log.LogError("Error occurred in file: " + compiler.CurrentDocumentName); 66 | return false; 67 | } 68 | 69 | return true; 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /LibCS2C/Util/FormattedStringBuilder.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | 3 | namespace LibCS2C.Util 4 | { 5 | public class FormattedStringBuilder 6 | { 7 | private StringBuilder m_sb; 8 | private string m_tabs; 9 | 10 | private bool m_alreadyIndented = false; 11 | 12 | private bool m_empty = true; 13 | 14 | /// 15 | /// Formatted string builder 16 | /// 17 | public FormattedStringBuilder() 18 | { 19 | m_sb = new StringBuilder(); 20 | m_tabs = ""; 21 | } 22 | 23 | /// 24 | /// Clears the buffer 25 | /// 26 | public void Clear() 27 | { 28 | m_sb.Clear(); 29 | m_empty = true; 30 | m_tabs = ""; 31 | } 32 | 33 | /// 34 | /// Adds a tab 35 | /// 36 | public void Indent() 37 | { 38 | m_tabs += "\t"; 39 | } 40 | 41 | /// 42 | /// Removes a tab 43 | /// 44 | public void UnIndent() 45 | { 46 | if (m_tabs.Length == 0) 47 | return; 48 | 49 | m_tabs = m_tabs.Substring(0, m_tabs.Length - 1); 50 | } 51 | 52 | /// 53 | /// Appends the indent tabs 54 | /// 55 | public void AppendIndent() 56 | { 57 | m_empty = false; 58 | m_sb.Append(m_tabs); 59 | } 60 | 61 | /// 62 | /// Appends text 63 | /// 64 | /// The text 65 | public void Append(string text) 66 | { 67 | if(!m_alreadyIndented) 68 | { 69 | m_alreadyIndented = true; 70 | AppendIndent(); 71 | } 72 | 73 | m_empty = false; 74 | m_sb.Append(text); 75 | } 76 | 77 | /// 78 | /// Appends text and a new line 79 | /// 80 | /// The text 81 | public void AppendLine(string text) 82 | { 83 | if(!m_alreadyIndented) 84 | { 85 | m_alreadyIndented = true; 86 | AppendIndent(); 87 | } 88 | 89 | m_empty = false; 90 | m_sb.AppendLine(text); 91 | m_alreadyIndented = false; 92 | } 93 | 94 | /// 95 | /// Checks if the stringbuilder is empty 96 | /// 97 | /// If it's empty 98 | public bool IsEmpty() 99 | { 100 | return m_empty; 101 | } 102 | 103 | /// 104 | /// Converts the buffer to a string 105 | /// 106 | /// The string 107 | public override string ToString() 108 | { 109 | return m_sb.ToString(); 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /LibCS2C/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | --------------------------------------------------------------------------------