Skip to content

Commit

Permalink
Generate nested struct if anonymous struct or union has a field name (#…
Browse files Browse the repository at this point in the history
…172)

* Global using

* Refactor `BaseGenerator`

* Refactor

* Don't generate node if it's using a C# built in type name

* Generate nested struct if anonymous struct or union has a field name

* Use parent struct name in nested struct
  • Loading branch information
lithiumtoast authored Jan 8, 2025
1 parent 117b013 commit 2a6a549
Show file tree
Hide file tree
Showing 21 changed files with 49 additions and 50 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
Expand Down
1 change: 0 additions & 1 deletion src/cs/production/c2cs.Tool/BuildCLibrary/Command.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.

using System;
using System.Collections.Immutable;
using System.CommandLine;
using System.Linq;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.

using System;
using System.Collections.Immutable;
using System.IO.Abstractions;
using System.Linq;
Expand Down
1 change: 0 additions & 1 deletion src/cs/production/c2cs.Tool/CommandLineHost.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.

using System;
using System.CommandLine;
using System.Threading;
using System.Threading.Tasks;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
Expand All @@ -27,7 +26,7 @@ public sealed partial class CodeGenerator
private readonly CodeGeneratorDocumentInteropRuntime _codeGeneratorDocumentInteropRuntime;

private readonly InputSanitized _input;
private readonly ImmutableDictionary<Type, BaseGenerator> _nodeCodeGenerators;
private readonly ImmutableDictionary<Type, object> _nodeCodeGenerators;

public CodeGenerator(
IServiceProvider services,
Expand All @@ -39,7 +38,7 @@ public CodeGenerator(
_codeGeneratorDocumentAssemblyAttributes = services.GetRequiredService<CodeGeneratorDocumentAssemblyAttributes>();
_codeGeneratorDocumentInteropRuntime = services.GetRequiredService<CodeGeneratorDocumentInteropRuntime>();

_nodeCodeGenerators = new Dictionary<Type, BaseGenerator>
_nodeCodeGenerators = new Dictionary<Type, object>
{
{ typeof(CEnum), services.GetRequiredService<GeneratorEnum>() },
{ typeof(CFunction), services.GetRequiredService<GeneratorFunction>() },
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using bottlenoselabs.Common.Tools;
Expand All @@ -19,7 +18,7 @@ public sealed class CodeGeneratorContext
#pragma warning disable IDE0032
private readonly NameMapper _nameMapper;
#pragma warning restore IDE0032
private readonly ImmutableDictionary<Type, BaseGenerator> _nodeCodeGenerators;
private readonly ImmutableDictionary<Type, object> _nodeCodeGenerators;
private readonly HashSet<string> _existingNamesCSharp = [];

public InputSanitized Input { get; }
Expand All @@ -31,7 +30,7 @@ public sealed class CodeGeneratorContext
public CodeGeneratorContext(
InputSanitized input,
CFfiCrossPlatform ffi,
ImmutableDictionary<Type, BaseGenerator> nodeCodeGenerators)
ImmutableDictionary<Type, object> nodeCodeGenerators)
{
Input = input;
Ffi = ffi;
Expand All @@ -46,6 +45,15 @@ public CodeGeneratorContext(
var codeGenerator = GetCodeGenerator<TNode>();

var nameCSharp = _nameMapper.GetNodeNameCSharp(node);
var nameCSharpCollidesWithBuiltInName = nameCSharp
// https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/built-in-types
is "bool" or "byte" or "sbyte" or "char" or "decimal" or "double" or "float" or "int" or "uint" or "nint"
or "nuint" or "long" or "ulong" or "short" or "ushort" or "object" or "string" or "dynamic";
if (nameCSharpCollidesWithBuiltInName)
{
return null;
}

var isAlreadyAdded = !_existingNamesCSharp.Add(nameCSharp);
if (isAlreadyAdded)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.

using System;
using System.Collections.Immutable;
using System.IO;
using System.Reflection;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.

using System;
using System.Globalization;
using System.Reflection;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
Expand Down
1 change: 0 additions & 1 deletion src/cs/production/c2cs.Tool/GenerateCSharpCode/Command.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.

using System;
using System.CommandLine;
using JetBrains.Annotations;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,10 @@

namespace C2CS.GenerateCSharpCode.Generators;

public abstract class BaseGenerator(ILogger<BaseGenerator> logger)
{
protected readonly ILogger<BaseGenerator> Logger = logger;

protected abstract string? GenerateCode(
string nameCSharp,
CodeGeneratorContext context,
object obj);
}

public abstract class BaseGenerator<TNode>(ILogger<BaseGenerator<TNode>> logger)
: BaseGenerator(logger)
where TNode : CNode
{
public abstract string? GenerateCode(CodeGeneratorContext context, string nameCSharp, TNode node);
protected readonly ILogger<BaseGenerator<TNode>> Logger = logger;

protected override string? GenerateCode(
string nameCSharp,
CodeGeneratorContext context,
object obj)
{
var node = (TNode)obj;
var code = GenerateCode(context, nameCSharp, node);
return code;
}
public abstract string? GenerateCode(CodeGeneratorContext context, string nameCSharp, TNode node);
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.

using System;
using System.Collections.Generic;
using System.Linq;
using c2ffi.Data;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,18 @@ public override string GenerateCode(CodeGeneratorContext context, string nameCSh

#pragma warning disable SA1202
internal static string GenerateCodeFunctionPointer(
NameMapper nameMapper, string name, CFunctionPointer node)
NameMapper nameMapper, string nameCSharp, CFunctionPointer node)
#pragma warning restore SA1202
{
var functionPointerTypeNameCSharp = GetFunctionPointerTypeNameCSharp(nameMapper, node);

var code = $$"""
[StructLayout(LayoutKind.Sequential)]
public partial struct {{name}}
public partial struct {{nameCSharp}}
{
public {{functionPointerTypeNameCSharp}} Pointer;
public {{name}}({{functionPointerTypeNameCSharp}} pointer)
public {{nameCSharp}}({{functionPointerTypeNameCSharp}} pointer)
{
Pointer = pointer;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.

using System.Collections.Immutable;
using System.Linq;
using c2ffi.Data.Nodes;
using JetBrains.Annotations;
using Microsoft.Extensions.Logging;
Expand All @@ -15,7 +16,7 @@ public class GeneratorStruct(ILogger<GeneratorStruct> logger)
public override string GenerateCode(CodeGeneratorContext context, string nameCSharp, CRecord record)
{
var codeStructMembers = GenerateCodeStructMembers(
context, record.Fields, record.NestedRecords, 0);
context, nameCSharp, record.Fields, record.NestedRecords, 0);
var membersCode = string.Join("\n\n", codeStructMembers);

var code = $$"""
Expand All @@ -31,11 +32,13 @@ public partial struct {{nameCSharp}}

private ImmutableArray<string> GenerateCodeStructMembers(
CodeGeneratorContext context,
string structNameCSharp,
ImmutableArray<CRecordField> fields,
ImmutableArray<CRecord> nestedStructs,
int parentFieldOffsetOf)
{
var codeFields = ImmutableArray.CreateBuilder<string>();
var codeNestedStructs = ImmutableArray.CreateBuilder<string>();

var nestedStructIndex = 0;
for (var i = 0; i < fields.Length; i++)
Expand All @@ -46,9 +49,25 @@ private ImmutableArray<string> GenerateCodeStructMembers(
if (field.Type.IsAnonymous ?? false)
{
var nestedStruct = nestedStructs[nestedStructIndex++];
var codeNestedStructMembers = GenerateCodeStructMembers(
context, nestedStruct.Fields, nestedStruct.NestedRecords, fieldOffsetOf);
codeFields.AddRange(codeNestedStructMembers);
var fieldNameCSharp = context.NameMapper.GetIdentifierCSharp(field.Name);
if (string.IsNullOrEmpty(fieldNameCSharp))
{
var codeNestedStructMembers = GenerateCodeStructMembers(
context, structNameCSharp, nestedStruct.Fields, nestedStruct.NestedRecords, fieldOffsetOf);
codeFields.AddRange(codeNestedStructMembers);
}
else
{
var fieldNameCSharpParts = fieldNameCSharp.Split('_', StringSplitOptions.RemoveEmptyEntries)
.Select(x => $"{x[0].ToString().ToUpperInvariant()}{x.AsSpan(1)}");
var nestedStructName = $"{structNameCSharp}_{string.Join('_', fieldNameCSharpParts)}";
var codeNestedStruct = GenerateCode(context, nestedStructName, nestedStruct);
codeNestedStructs.Add(codeNestedStruct);

var codeField = GenerateCodeStructField(
context.NameMapper, field, fieldNameCSharp, nestedStructName, fieldOffsetOf);
codeFields.Add(codeField);
}
}
else
{
Expand All @@ -60,7 +79,8 @@ private ImmutableArray<string> GenerateCodeStructMembers(
}
}

return codeFields.ToImmutable();
var result = codeFields.ToImmutable().AddRange(codeNestedStructs.ToImmutable());
return result;
}

private string GenerateCodeStructField(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
Expand Down
3 changes: 2 additions & 1 deletion src/cs/production/c2cs.Tool/GenerateCSharpCode/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ public static void ConfigureServices(IServiceCollection services)
private static void AddNodeCodeGenerators(IServiceCollection services)
{
var assembly = Assembly.GetExecutingAssembly();
var types = assembly.GetTypes().Where(p => !p.IsAbstract && typeof(BaseGenerator).IsAssignableFrom(p))
var types = assembly.GetTypes().Where(t =>
t is { IsAbstract: false, IsInterface: false, IsGenericType: false, BaseType.IsGenericType: true } && t.BaseType.GetGenericTypeDefinition() == typeof(BaseGenerator<>))
.ToImmutableArray();
foreach (var type in types)
{
Expand Down
1 change: 0 additions & 1 deletion src/cs/production/c2cs.Tool/GenerateCSharpCode/Tool.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.

using System;
using System.IO;
using System.IO.Abstractions;
using bottlenoselabs.Common.Tools;
Expand Down
4 changes: 4 additions & 0 deletions src/cs/production/c2cs.Tool/GlobalUsings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.

global using System;
1 change: 0 additions & 1 deletion src/cs/production/c2cs.Tool/Program.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.

using System;
using Microsoft.Extensions.Hosting;

namespace C2CS;
Expand Down
1 change: 0 additions & 1 deletion src/cs/production/c2cs.Tool/Startup.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Copyright (c) Bottlenose Labs Inc. (https://github.com/bottlenoselabs). All rights reserved.
// Licensed under the MIT license. See LICENSE file in the Git repository root directory for full license information.

using System;
using System.Collections.Immutable;
using System.IO;
using System.IO.Abstractions;
Expand Down

0 comments on commit 2a6a549

Please sign in to comment.