Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

InteropGen cleanup #57

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
7fdea40
Refactor units to be readonly
peter-r-g Mar 9, 2023
dc1eddf
Make units sealed classes
peter-r-g Mar 9, 2023
ec926ae
Rename Field > Variable
peter-r-g Mar 9, 2023
596f716
Rename Structure > Struct
peter-r-g Mar 9, 2023
4b305bc
Fix fields not updating in Parser
peter-r-g Mar 9, 2023
d33482f
Minor changes
peter-r-g Mar 9, 2023
6534660
Add early bail to method parsing
peter-r-g Mar 9, 2023
957141f
Move constructor logic
peter-r-g Mar 9, 2023
2302bb4
Add destructor method parsing
peter-r-g Mar 9, 2023
ee9732f
Move HasGenerateBindingsAttribute to extension method
peter-r-g Mar 9, 2023
dcb7499
Minor changes
peter-r-g Mar 9, 2023
83605a1
Make Parser.GetUnits return IEnumerable instead
peter-r-g Mar 9, 2023
d9de125
Make BaseCodeGenerator.GetHeader a static property
peter-r-g Mar 9, 2023
b3921bd
Minor change
peter-r-g Mar 9, 2023
e9f1ace
Update ThreadDispatcher to Mocha.Common version
peter-r-g Mar 9, 2023
2c1d882
Drop sleep timer on waiting for thread dispatcher
peter-r-g Mar 9, 2023
36c919b
Tweak ThreadDispatcher namespace
peter-r-g Mar 9, 2023
c9c2664
Refactor units to be readonly
peter-r-g Mar 9, 2023
0ed975a
Make units sealed classes
peter-r-g Mar 9, 2023
ae59d0c
Rename Field > Variable
peter-r-g Mar 9, 2023
065d841
Rename Structure > Struct
peter-r-g Mar 9, 2023
3b0083a
Fix fields not updating in Parser
peter-r-g Mar 9, 2023
f056e3e
Minor changes
peter-r-g Mar 9, 2023
f0b6440
Add early bail to method parsing
peter-r-g Mar 9, 2023
203f070
Move constructor logic
peter-r-g Mar 9, 2023
321f958
Add destructor method parsing
peter-r-g Mar 9, 2023
d0a3cba
Move HasGenerateBindingsAttribute to extension method
peter-r-g Mar 9, 2023
bef236c
Minor changes
peter-r-g Mar 9, 2023
c068836
Make Parser.GetUnits return IEnumerable instead
peter-r-g Mar 9, 2023
5641148
Make BaseCodeGenerator.GetHeader a static property
peter-r-g Mar 9, 2023
e14e791
Minor change
peter-r-g Mar 9, 2023
bb6eb45
Update ThreadDispatcher to Mocha.Common version
peter-r-g Mar 9, 2023
f203dad
Drop sleep timer on waiting for thread dispatcher
peter-r-g Mar 9, 2023
73fc8a7
Tweak ThreadDispatcher namespace
peter-r-g Mar 9, 2023
df59f55
Merge branch 'peter-r-g/interop-gen-cleanup' of https://github.com/pe…
peter-r-g Mar 10, 2023
9eece4e
Refactor code generators
peter-r-g Mar 10, 2023
7b77b44
Remove refs on reference type parameters
peter-r-g Mar 10, 2023
b594a59
Lots of cleanup
peter-r-g Mar 10, 2023
d5bdcf1
Internalize/privatize everything
peter-r-g Mar 13, 2023
282e839
Documentation pass on Unit items
peter-r-g Mar 13, 2023
93ff2bc
Cleanup VcxprojParser
peter-r-g Mar 13, 2023
becc7a1
Documentation pass
peter-r-g Mar 15, 2023
04bcd3b
Switch to ILogger instead of Console writing
peter-r-g Mar 15, 2023
316fce7
Cleanup
peter-r-g Mar 15, 2023
ef57a22
Fix launchSettings.json working directory
peter-r-g Mar 15, 2023
c0cde01
Initialize lookup table once statically
peter-r-g Mar 15, 2023
2af966f
Only search Mocha.Host project for headers
peter-r-g Mar 15, 2023
e477302
Filter files by *.h instead of grabbing all
peter-r-g Mar 15, 2023
e643517
Document code generators
peter-r-g Mar 17, 2023
ec7ba13
Move extensions to separate namespace
peter-r-g Mar 17, 2023
7c791ab
Move code generators to separate namespace
peter-r-g Mar 17, 2023
3e0fdce
Move parsing items to separate namespace
peter-r-g Mar 17, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 0 additions & 26 deletions Source/MochaTool.InteropGen/CodeGen/BaseCodeGenerator.cs

This file was deleted.

188 changes: 114 additions & 74 deletions Source/MochaTool.InteropGen/CodeGen/ManagedCodeGenerator.cs
Original file line number Diff line number Diff line change
@@ -1,31 +1,103 @@
using System.CodeDom.Compiler;
using MochaTool.InteropGen.Parsing;
using System.CodeDom.Compiler;
using System.Collections.Immutable;

namespace MochaTool.InteropGen;
namespace MochaTool.InteropGen.CodeGen;

sealed class ManagedCodeGenerator : BaseCodeGenerator
/// <summary>
/// Contains functionality for generating C# code.
/// </summary>
internal static class ManagedCodeGenerator
{
public ManagedCodeGenerator( List<IUnit> units ) : base( units )
/// <summary>
/// The namespace that all generated code will be under.
/// </summary>
private const string Namespace = "Mocha.Glue";

/// <summary>
/// An array containing all using declarations for generated code.
/// </summary>
private static readonly string[] Usings = new[]
{
}

private List<string> GetUsings()
"System.Runtime.InteropServices",
"System.Runtime.Serialization",
"Mocha.Common"
};

/// <summary>
/// The header to be used at the top of generated code.
/// </summary>
private static string Header => $"""
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// InteropGen generated on {DateTime.Now}
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
""";

/// <summary>
/// Generates and returns C# code for a set of <see cref="IUnit"/>s.
/// </summary>
/// <param name="units">An enumerable list of <see cref="IUnit"/>s to generate code for.</param>
/// <returns>C# code representing the set of <see cref="IUnit"/>s passed.</returns>
internal static string GenerateCode( IEnumerable<IUnit> units )
{
return new() { "System.Runtime.InteropServices", "System.Runtime.Serialization", "Mocha.Common" };
}
var (baseTextWriter, writer) = Utils.CreateWriter();

private string GetNamespace()
{
return "Mocha.Glue";
// Write header.
writer.WriteLine( Header );
writer.WriteLine();

// Write using statements.
foreach ( var usingStatement in Usings )
writer.WriteLine( $"using {usingStatement};" );

// Write namespace.
writer.WriteLine();
writer.WriteLine( $"namespace {Namespace};" );
writer.WriteLine();

// Write each unit.
foreach ( var unit in units )
{
switch ( unit )
{
case Class c when c.IsNamespace:
GenerateNamespaceCode( writer, c );
break;
case Class c:
GenerateClassCode( writer, c );
break;
case Struct s:
GenerateStructCode( writer, s );
break;
default:
continue;
}

writer.WriteLine();
}

return baseTextWriter.ToString();
}

private void GenerateClassCode( ref IndentedTextWriter writer, Class sel )
/// <summary>
/// Generates C# code for a class.
/// </summary>
/// <param name="writer">The writer to append the code to.</param>
/// <param name="c">The class to write code for.</param>
private static void GenerateClassCode( IndentedTextWriter writer, Class c )
{
//
// Gather everything we need into nice lists
//
List<string> decls = new();

foreach ( var method in sel.Methods )
foreach ( var method in c.Methods )
{
var returnType = Utils.GetManagedType( method.ReturnType );
var name = method.Name;
Expand Down Expand Up @@ -56,13 +128,13 @@ private void GenerateClassCode( ref IndentedTextWriter writer, Class sel )
// any parameters. The return type is the last type argument passed to
// the delegate.
//
decls.Add( $"private static {delegateSignature} _{name} = ({delegateSignature})Mocha.Common.Global.UnmanagedArgs.__{sel.Name}_{name}MethodPtr;" );
decls.Add( $"private static {delegateSignature} _{name} = ({delegateSignature})Mocha.Common.Global.UnmanagedArgs.__{c.Name}_{name}MethodPtr;" );
}

//
// Write shit
//
writer.WriteLine( $"public unsafe class {sel.Name} : INativeGlue" );
writer.WriteLine( $"public unsafe class {c.Name} : INativeGlue" );
writer.WriteLine( "{" );
writer.Indent++;

Expand All @@ -71,18 +143,16 @@ private void GenerateClassCode( ref IndentedTextWriter writer, Class sel )
// Decls
writer.WriteLine();
foreach ( var decl in decls )
{
writer.WriteLine( decl );
}
writer.WriteLine();

// Ctor
if ( sel.Methods.Any( x => x.IsConstructor ) )
if ( c.Methods.Any( x => x.IsConstructor ) )
{
var ctor = sel.Methods.First( x => x.IsConstructor );
var ctor = c.Methods.First( x => x.IsConstructor );
var managedCtorArgs = string.Join( ", ", ctor.Parameters.Select( x => $"{Utils.GetManagedType( x.Type )} {x.Name}" ) );

writer.WriteLine( $"public {sel.Name}( {managedCtorArgs} )" );
writer.WriteLine( $"public {c.Name}( {managedCtorArgs} )" );
writer.WriteLine( "{" );
writer.Indent++;

Expand All @@ -94,7 +164,7 @@ private void GenerateClassCode( ref IndentedTextWriter writer, Class sel )
}

// Methods
foreach ( var method in sel.Methods )
foreach ( var method in c.Methods )
{
writer.WriteLine();

Expand Down Expand Up @@ -122,7 +192,7 @@ private void GenerateClassCode( ref IndentedTextWriter writer, Class sel )
writer.Indent++;

// Spin up a MemoryContext instance
writer.WriteLine( $"using var ctx = new MemoryContext( \"{sel.Name}.{name}\" );" );
writer.WriteLine( $"using var ctx = new MemoryContext( \"{c.Name}.{name}\" );" );

//
// Gather function body
Expand All @@ -131,7 +201,7 @@ private void GenerateClassCode( ref IndentedTextWriter writer, Class sel )

// We need to pass the instance in if this is not a static method
if ( !method.IsStatic )
paramsAndInstance = paramsAndInstance.Prepend( new Variable( "NativePtr", "IntPtr" ) ).ToList();
paramsAndInstance = paramsAndInstance.Prepend( new Variable( "NativePtr", "IntPtr" ) ).ToImmutableArray();

// Gather function call arguments. Make sure that we're passing in a pointer for everything
var paramNames = paramsAndInstance.Select( x => "ctx.GetPtr( " + x.Name + " )" );
Expand Down Expand Up @@ -175,30 +245,38 @@ private void GenerateClassCode( ref IndentedTextWriter writer, Class sel )
writer.WriteLine( "}" );
}

private void GenerateStructCode( ref IndentedTextWriter writer, Structure sel )
/// <summary>
/// Generates C# code for a struct.
/// </summary>
/// <param name="writer">The writer to append the code to.</param>
/// <param name="s">The struct to write code for.</param>
private static void GenerateStructCode( IndentedTextWriter writer, Struct s )
{
writer.WriteLine( $"[StructLayout( LayoutKind.Sequential )]" );
writer.WriteLine( $"public struct {sel.Name}" );
writer.WriteLine( $"public struct {s.Name}" );
writer.WriteLine( "{" );
writer.Indent++;

foreach ( var field in sel.Fields )
{
foreach ( var field in s.Fields )
writer.WriteLine( $"public {Utils.GetManagedType( field.Type )} {field.Name};" );
}

writer.Indent--;
writer.WriteLine( "}" );
}

private void GenerateNamespaceCode( ref IndentedTextWriter writer, Class sel )
/// <summary>
/// Generates C# code for a namespace.
/// </summary>
/// <param name="writer">The writer to append the code to.</param>
/// <param name="ns">The namespace to write code for.</param>
private static void GenerateNamespaceCode( IndentedTextWriter writer, Class ns )
{
//
// Gather everything we need into nice lists
//
List<string> decls = new();

foreach ( var method in sel.Methods )
foreach ( var method in ns.Methods )
{
var returnType = Utils.GetManagedType( method.ReturnType );
var name = method.Name;
Expand All @@ -220,24 +298,22 @@ private void GenerateNamespaceCode( ref IndentedTextWriter writer, Class sel )
// any parameters. The return type is the last type argument passed to
// the delegate.
//
decls.Add( $"private static {delegateSignature} _{name} = ({delegateSignature})Mocha.Common.Global.UnmanagedArgs.__{sel.Name}_{name}MethodPtr;" );
decls.Add( $"private static {delegateSignature} _{name} = ({delegateSignature})Mocha.Common.Global.UnmanagedArgs.__{ns.Name}_{name}MethodPtr;" );
}

//
// Write shit
//
writer.WriteLine( $"public static unsafe class {sel.Name}" );
writer.WriteLine( $"public static unsafe class {ns.Name}" );
writer.WriteLine( "{" );
writer.Indent++;

writer.WriteLine();
foreach ( var decl in decls )
{
writer.WriteLine( decl );
}

// Methods
foreach ( var method in sel.Methods )
foreach ( var method in ns.Methods )
{
writer.WriteLine();

Expand All @@ -252,10 +328,9 @@ private void GenerateNamespaceCode( ref IndentedTextWriter writer, Class sel )
writer.Indent++;

// Spin up a MemoryContext instance
writer.WriteLine( $"using var ctx = new MemoryContext( \"{sel.Name}.{name}\" );" );
writer.WriteLine( $"using var ctx = new MemoryContext( \"{ns.Name}.{name}\" );" );

var @params = method.Parameters;
var paramNames = @params.Select( x => "ctx.GetPtr( " + x.Name + " )" );
var paramNames = method.Parameters.Select( x => "ctx.GetPtr( " + x.Name + " )" );
var functionCallArgs = string.Join( ", ", paramNames );

if ( returnsPointer )
Expand Down Expand Up @@ -293,39 +368,4 @@ private void GenerateNamespaceCode( ref IndentedTextWriter writer, Class sel )
writer.Indent--;
writer.WriteLine( "}" );
}

public string GenerateManagedCode()
{
var (baseTextWriter, writer) = Utils.CreateWriter();

writer.WriteLine( GetHeader() );
writer.WriteLine();

foreach ( var usingStatement in GetUsings() )
writer.WriteLine( $"using {usingStatement};" );

writer.WriteLine();
writer.WriteLine( $"namespace {GetNamespace()};" );
writer.WriteLine();

foreach ( var unit in Units )
{
if ( unit is Class c )
{
if ( c.IsNamespace )
GenerateNamespaceCode( ref writer, c );
else
GenerateClassCode( ref writer, c );
}

if ( unit is Structure s )
{
GenerateStructCode( ref writer, s );
}

writer.WriteLine();
}

return baseTextWriter.ToString();
}
}
Loading