diff --git a/Cesium.CodeGen.Tests/CodeGenMethodTests.PrimitiveTypes.verified.txt b/Cesium.CodeGen.Tests/CodeGenMethodTests.PrimitiveTypes.verified.txt new file mode 100644 index 00000000..671c63c7 --- /dev/null +++ b/Cesium.CodeGen.Tests/CodeGenMethodTests.PrimitiveTypes.verified.txt @@ -0,0 +1,7 @@ +System.Int32 ::main() + Locals: + System.Byte V_0 + System.Int32 V_1 + System.Byte V_2 + IL_0000: ldc.i4 0 + IL_0005: ret diff --git a/Cesium.CodeGen.Tests/CodeGenMethodTests.cs b/Cesium.CodeGen.Tests/CodeGenMethodTests.cs index b56cab35..312ed602 100644 --- a/Cesium.CodeGen.Tests/CodeGenMethodTests.cs +++ b/Cesium.CodeGen.Tests/CodeGenMethodTests.cs @@ -118,4 +118,17 @@ public void IncorrectOverrideCliImport() => DoesNotCompile(@"__cli_import(""Syst [Fact] public void NoDefinition() => DoesNotCompile(@"int foo(void); int main() { return foo(); }", "Function foo not defined."); + + [Fact] + public Task PrimitiveTypes() => DoTest(@"int main(void) +{ + // basic + char a; + int b; + + // unsigned + unsigned char c; + + return 0; +}"); } diff --git a/Cesium.CodeGen.Tests/CodeGenPrimitiveTypeTests.cs b/Cesium.CodeGen.Tests/CodeGenPrimitiveTypeTests.cs new file mode 100644 index 00000000..9173dc8b --- /dev/null +++ b/Cesium.CodeGen.Tests/CodeGenPrimitiveTypeTests.cs @@ -0,0 +1,25 @@ +using Cesium.CodeGen.Ir.Declarations; +using Cesium.CodeGen.Ir.Types; +using Cesium.Parser; +using Yoakke.SynKit.C.Syntax; + +namespace Cesium.CodeGen.Tests; + +public class CodeGenPrimitiveTypeTests +{ + [Theory] + [InlineData("char", PrimitiveTypeKind.Char)] + [InlineData("int", PrimitiveTypeKind.Int)] + [InlineData("void", PrimitiveTypeKind.Void)] + [InlineData("unsigned char", PrimitiveTypeKind.UnsignedChar)] + internal void Test(string typeString, PrimitiveTypeKind expectedKind) + { + var source = $"{typeString} x;"; + var parser = new CParser(new CLexer(source)); + var ast = parser.ParseDeclaration().Ok.Value; + var declarationInfo = (ScopedIdentifierDeclaration)IScopedDeclarationInfo.Of(ast); + var item = declarationInfo.Items.Single(); + var type = (PrimitiveType)item.Declaration.Type; + Assert.Equal(expectedKind, type.Kind); + } +} diff --git a/Cesium.CodeGen/Cesium.CodeGen.csproj b/Cesium.CodeGen/Cesium.CodeGen.csproj index 2551e5fa..60717971 100644 --- a/Cesium.CodeGen/Cesium.CodeGen.csproj +++ b/Cesium.CodeGen/Cesium.CodeGen.csproj @@ -16,4 +16,8 @@ + + + + diff --git a/Cesium.CodeGen/Ir/Declarations/LocalDeclarationInfo.cs b/Cesium.CodeGen/Ir/Declarations/LocalDeclarationInfo.cs index 2625e915..9e0d932a 100644 --- a/Cesium.CodeGen/Ir/Declarations/LocalDeclarationInfo.cs +++ b/Cesium.CodeGen/Ir/Declarations/LocalDeclarationInfo.cs @@ -14,7 +14,7 @@ internal record LocalDeclarationInfo( ParametersInfo? Parameters, string? CliImportMemberName) { - public static LocalDeclarationInfo Of(ICollection specifiers, Declarator? declarator) + public static LocalDeclarationInfo Of(IReadOnlyList specifiers, Declarator? declarator) { var (type, cliImportMemberName) = ProcessSpecifiers(specifiers); if (declarator == null) @@ -85,13 +85,14 @@ public static LocalDeclarationInfo Of(ICollection specifi } private static (IType, string? cliImportMemberName) ProcessSpecifiers( - ICollection specifiers) + IReadOnlyList specifiers) { IType? type = null; var isConst = false; string? cliImportMemberName = null; - foreach (var specifier in specifiers) + for (var i = 0; i < specifiers.Count; ++i) { + var specifier = specifiers[i]; switch (specifier) { case SimpleTypeSpecifier ts: @@ -99,14 +100,7 @@ private static (IType, string? cliImportMemberName) ProcessSpecifiers( throw new NotSupportedException( $"Unsupported type definition after already resolved type {type}: {ts}."); - type = new PrimitiveType(ts.TypeName switch - { - "char" => PrimitiveTypeKind.Char, - "int" => PrimitiveTypeKind.Int, - "void" => PrimitiveTypeKind.Void, - var unknown => - throw new NotImplementedException($"Not supported yet type specifier: {unknown}.") - }); + type = ProcessSimpleTypeSpecifiers(ts, specifiers, ref i); break; case NamedTypeSpecifier nt: @@ -195,4 +189,39 @@ private static IEnumerable GetTypeMemberDeclarations( }); }); } + + private static IType ProcessSimpleTypeSpecifiers( + SimpleTypeSpecifier first, + IReadOnlyList specifiers, + ref int i) + { + var allSpecifiers = new List { first }; + while (specifiers.Count > i + 1 && specifiers[i + 1] is SimpleTypeSpecifier next) + { + allSpecifiers.Add(next); + ++i; + } + + var typeNames = allSpecifiers.Select(ts => + { + ts.Deconstruct(out var typeName); + return typeName; + }).ToList(); + + return typeNames switch + { + { Count: 1 } => new PrimitiveType(typeNames.Single() switch + { + "char" => PrimitiveTypeKind.Char, + "int" => PrimitiveTypeKind.Int, + "void" => PrimitiveTypeKind.Void, + var unknown => + throw new NotImplementedException($"Not supported yet type specifier: {unknown}.") + }), + { Count: 2 } when typeNames[0] == "unsigned" && typeNames[1] == "char" => + new PrimitiveType(PrimitiveTypeKind.UnsignedChar), + _ => throw new NotImplementedException( + $"Simple type specifiers are not supported: {string.Join(" ", typeNames)}") + }; + } } diff --git a/Cesium.CodeGen/Ir/Declarations/ScopedDeclarationInfo.cs b/Cesium.CodeGen/Ir/Declarations/ScopedDeclarationInfo.cs index 1fb00e22..2cd6059e 100644 --- a/Cesium.CodeGen/Ir/Declarations/ScopedDeclarationInfo.cs +++ b/Cesium.CodeGen/Ir/Declarations/ScopedDeclarationInfo.cs @@ -25,7 +25,7 @@ public static IScopedDeclarationInfo Of(Declaration declaration) } private static TypeDefDeclaration TypeDefOf( - ICollection specifiers, + IReadOnlyList specifiers, IEnumerable initDeclarators) { var declarations = initDeclarators.Select(d => @@ -41,7 +41,7 @@ private static TypeDefDeclaration TypeDefOf( } private static ScopedIdentifierDeclaration IdentifierOf( - ICollection specifiers, + IReadOnlyList specifiers, IEnumerable initDeclarators) { var declarations = initDeclarators @@ -52,7 +52,7 @@ private static ScopedIdentifierDeclaration IdentifierOf( } private static InitializableDeclarationInfo IdentifierOf( - ICollection specifiers, + IReadOnlyList specifiers, InitDeclarator initDeclarator) { var (declarator, initializer) = initDeclarator; diff --git a/Cesium.CodeGen/Ir/Types/PrimitiveType.cs b/Cesium.CodeGen/Ir/Types/PrimitiveType.cs index 0220b93f..559bb556 100644 --- a/Cesium.CodeGen/Ir/Types/PrimitiveType.cs +++ b/Cesium.CodeGen/Ir/Types/PrimitiveType.cs @@ -5,9 +5,13 @@ namespace Cesium.CodeGen.Ir.Types; internal enum PrimitiveTypeKind { + // Basic Char, Int, - Void + Void, + + // Unsigned + UnsignedChar } internal record PrimitiveType(PrimitiveTypeKind Kind) : IType @@ -17,9 +21,14 @@ public TypeReference Resolve(TranslationUnitContext context) var typeSystem = context.TypeSystem; return Kind switch { + // Basic PrimitiveTypeKind.Char => typeSystem.Byte, PrimitiveTypeKind.Int => typeSystem.Int32, PrimitiveTypeKind.Void => typeSystem.Void, + + // Unsigned + PrimitiveTypeKind.UnsignedChar => typeSystem.Byte, + _ => throw new NotImplementedException($"Primitive type not supported, yet: {this}.") }; }