Skip to content

Commit

Permalink
(#72) CodeGen: support unsigned char type
Browse files Browse the repository at this point in the history
  • Loading branch information
ForNeVeR committed Feb 20, 2022
1 parent e864125 commit 3fb229f
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 15 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
System.Int32 <Module>::main()
Locals:
System.Byte V_0
System.Int32 V_1
System.Byte V_2
IL_0000: ldc.i4 0
IL_0005: ret
13 changes: 13 additions & 0 deletions Cesium.CodeGen.Tests/CodeGenMethodTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}");
}
25 changes: 25 additions & 0 deletions Cesium.CodeGen.Tests/CodeGenPrimitiveTypeTests.cs
Original file line number Diff line number Diff line change
@@ -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);
}
}
4 changes: 4 additions & 0 deletions Cesium.CodeGen/Cesium.CodeGen.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,8 @@
<ProjectReference Include="..\Cesium.Runtime\Cesium.Runtime.csproj" />
</ItemGroup>

<ItemGroup>
<InternalsVisibleTo Include="Cesium.CodeGen.Tests" />
</ItemGroup>

</Project>
51 changes: 40 additions & 11 deletions Cesium.CodeGen/Ir/Declarations/LocalDeclarationInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ internal record LocalDeclarationInfo(
ParametersInfo? Parameters,
string? CliImportMemberName)
{
public static LocalDeclarationInfo Of(ICollection<IDeclarationSpecifier> specifiers, Declarator? declarator)
public static LocalDeclarationInfo Of(IReadOnlyList<IDeclarationSpecifier> specifiers, Declarator? declarator)
{
var (type, cliImportMemberName) = ProcessSpecifiers(specifiers);
if (declarator == null)
Expand Down Expand Up @@ -85,28 +85,22 @@ public static LocalDeclarationInfo Of(ICollection<IDeclarationSpecifier> specifi
}

private static (IType, string? cliImportMemberName) ProcessSpecifiers(
ICollection<IDeclarationSpecifier> specifiers)
IReadOnlyList<IDeclarationSpecifier> 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:
if (type != null)
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:
Expand Down Expand Up @@ -195,4 +189,39 @@ private static IEnumerable<LocalDeclarationInfo> GetTypeMemberDeclarations(
});
});
}

private static IType ProcessSimpleTypeSpecifiers(
SimpleTypeSpecifier first,
IReadOnlyList<IDeclarationSpecifier> specifiers,
ref int i)
{
var allSpecifiers = new List<SimpleTypeSpecifier> { 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)}")
};
}
}
6 changes: 3 additions & 3 deletions Cesium.CodeGen/Ir/Declarations/ScopedDeclarationInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public static IScopedDeclarationInfo Of(Declaration declaration)
}

private static TypeDefDeclaration TypeDefOf(
ICollection<IDeclarationSpecifier> specifiers,
IReadOnlyList<IDeclarationSpecifier> specifiers,
IEnumerable<InitDeclarator> initDeclarators)
{
var declarations = initDeclarators.Select(d =>
Expand All @@ -41,7 +41,7 @@ private static TypeDefDeclaration TypeDefOf(
}

private static ScopedIdentifierDeclaration IdentifierOf(
ICollection<IDeclarationSpecifier> specifiers,
IReadOnlyList<IDeclarationSpecifier> specifiers,
IEnumerable<InitDeclarator> initDeclarators)
{
var declarations = initDeclarators
Expand All @@ -52,7 +52,7 @@ private static ScopedIdentifierDeclaration IdentifierOf(
}

private static InitializableDeclarationInfo IdentifierOf(
ICollection<IDeclarationSpecifier> specifiers,
IReadOnlyList<IDeclarationSpecifier> specifiers,
InitDeclarator initDeclarator)
{
var (declarator, initializer) = initDeclarator;
Expand Down
11 changes: 10 additions & 1 deletion Cesium.CodeGen/Ir/Types/PrimitiveType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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}.")
};
}
Expand Down

0 comments on commit 3fb229f

Please sign in to comment.