├── .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 |
--------------------------------------------------------------------------------