Skip to content

Commit

Permalink
(#72) IR: support type generation for structs
Browse files Browse the repository at this point in the history
  • Loading branch information
ForNeVeR committed Feb 12, 2022
1 parent f349c28 commit a586b1a
Show file tree
Hide file tree
Showing 15 changed files with 133 additions and 31 deletions.
6 changes: 3 additions & 3 deletions Cesium.Ast/Declarations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public interface IDeclarationSpecifier { }
public record StorageClassSpecifier(string Name) : IDeclarationSpecifier;

// 6.7.2 Type specifiers
public interface ITypeSpecifier : ISpecifierQualifierListItem, IDeclarationSpecifier { }
public interface ITypeSpecifier : ISpecifierQualifierListItem { }

public record SimpleTypeSpecifier(string TypeName) : ITypeSpecifier;
public record StructOrUnionSpecifier(
Expand All @@ -33,12 +33,12 @@ public record StructDeclaration(
ImmutableArray<ISpecifierQualifierListItem> SpecifiersQualifiers,
ImmutableArray<StructDeclarator>? Declarators);

public interface ISpecifierQualifierListItem {}
public interface ISpecifierQualifierListItem : IDeclarationSpecifier {}

public record StructDeclarator(Declarator Declarator);

// 6.7.3 Type qualifiers
public record TypeQualifier(string Name) : IDeclarationSpecifier, ISpecifierQualifierListItem;
public record TypeQualifier(string Name) : ISpecifierQualifierListItem;

// 6.7.7 Type names
public record AbstractDeclarator(Pointer? Pointer = null, IDirectAbstractDeclarator? DirectAbstractDeclarator = null);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Module: Primary
Type: <Module>

Type: foo
Fields:
System.Int32 foo::x
Init with: []
14 changes: 13 additions & 1 deletion Cesium.CodeGen/Contexts/TranslationUnitContext.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Cesium.CodeGen.Contexts.Meta;
using Cesium.CodeGen.Ir.Types;
using Mono.Cecil;

namespace Cesium.CodeGen.Contexts;
Expand All @@ -10,5 +11,16 @@ public record TranslationUnitContext(AssemblyContext AssemblyContext)
public TypeSystem TypeSystem => Module.TypeSystem;
public TypeDefinition ModuleType => Module.GetType("<Module>");
internal Dictionary<string, FunctionInfo> Functions => AssemblyContext.Functions;
internal Dictionary<string, TypeReference> Types { get; } = new();

private readonly Dictionary<INamedType, TypeReference> _generatedTypes = new();
private readonly Dictionary<string, TypeReference> _types = new();

internal void GenerateType(INamedType type, string name)
{
var typeReference = type.Emit(name, this);
_generatedTypes.Add(type, typeReference);
_types.Add(name, typeReference);
}

internal TypeReference? GetTypeReference(INamedType type) => _generatedTypes.GetValueOrDefault(type);
}
12 changes: 8 additions & 4 deletions Cesium.CodeGen/Extensions/TypeDefinitionEx.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Cesium.CodeGen.Contexts;
using Cesium.CodeGen.Ir;
using Mono.Cecil;

Expand All @@ -7,7 +8,7 @@ internal static class TypeDefinitionEx
{
public static MethodDefinition DefineMethod(
this TypeDefinition type,
TypeSystem typeSystem,
TranslationUnitContext context,
string name,
TypeReference returnType,
ParametersInfo? parameters)
Expand All @@ -16,12 +17,15 @@ public static MethodDefinition DefineMethod(
name,
MethodAttributes.Public | MethodAttributes.Static,
returnType);
AddParameters(typeSystem, method, parameters);
AddParameters(context, method, parameters);
type.Methods.Add(method);
return method;
}

private static void AddParameters(TypeSystem typeSystem, MethodDefinition method, ParametersInfo? parametersInfo)
private static void AddParameters(
TranslationUnitContext context,
MethodReference method,
ParametersInfo? parametersInfo)
{
if (parametersInfo == null) return;
var (parameters, isVoid, isVarArg) = parametersInfo;
Expand All @@ -34,7 +38,7 @@ private static void AddParameters(TypeSystem typeSystem, MethodDefinition method
foreach (var parameter in parameters)
{
var (type, name) = parameter;
var parameterDefinition = new ParameterDefinition(type.Resolve(typeSystem))
var parameterDefinition = new ParameterDefinition(type.Resolve(context))
{
Name = name
};
Expand Down
2 changes: 1 addition & 1 deletion Cesium.CodeGen/Extensions/TypeSystemEx.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

namespace Cesium.CodeGen.Extensions;

public static class TypeSystemEx
internal static class TypeSystemEx
{
public static MethodReference? MethodLookup(this TranslationUnitContext context, string memberName)
{
Expand Down
2 changes: 1 addition & 1 deletion Cesium.CodeGen/Ir/BlockItems/DeclarationBlockItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ private static void EmitScopedIdentifier(FunctionScope scope, ScopedIdentifierDe
throw new NotSupportedException(
$"Local declaration with a CLI import member name {cliImportMemberName} isn't supported.");

var typeReference = type.Resolve(scope.TypeSystem);
var typeReference = type.Resolve(scope.Context);
var variable = new VariableDefinition(typeReference);
method.Body.Variables.Add(variable);
scope.Variables.Add(identifier, variable);
Expand Down
25 changes: 24 additions & 1 deletion Cesium.CodeGen/Ir/Declarations/LocalDeclarationInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ private static (IType, string? cliImportMemberName) ProcessSpecifiers(
if (identifier != null)
throw new NotImplementedException($"Named structures aren't supported, yet: {identifier}.");

type = new StructType(structDeclarations);
type = new StructType(GetTypeMemberDeclarations(structDeclarations));
break;
}

Expand All @@ -163,4 +163,27 @@ private static (IType, string? cliImportMemberName) ProcessSpecifiers(

return (isConst ? new ConstType(type) : type, cliImportMemberName);
}

private static IEnumerable<LocalDeclarationInfo> GetTypeMemberDeclarations(
IEnumerable<StructDeclaration> structDeclarations)
{
return structDeclarations.SelectMany(memberDeclarator =>
{
var (specifiersQualifiers, declarators) = memberDeclarator;
if (declarators == null)
throw new NotSupportedException(
"Empty declarator list on a struct member declaration:" +
$"{string.Join(", ", specifiersQualifiers)}.");

var collection = specifiersQualifiers
.Select<ISpecifierQualifierListItem, IDeclarationSpecifier>(x => x)
.ToList();

return declarators.Select<StructDeclarator, LocalDeclarationInfo>(d =>
{
d.Deconstruct(out var declarator);
return Of(collection, declarator);
});
});
}
}
4 changes: 2 additions & 2 deletions Cesium.CodeGen/Ir/TopLevel/FunctionDefinition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public FunctionDefinition(Ast.FunctionDefinition function)

public void EmitTo(TranslationUnitContext context)
{
var returnType = _returnType.Resolve(context.TypeSystem);
var returnType = _returnType.Resolve(context);
if (IsMain && returnType != context.TypeSystem.Int32)
throw new NotSupportedException(
$"Invalid return type for the {_name} function: " +
Expand All @@ -56,7 +56,7 @@ public void EmitTo(TranslationUnitContext context)

var method = declaration switch
{
null => context.ModuleType.DefineMethod(context.TypeSystem, _name, returnType, _parameters),
null => context.ModuleType.DefineMethod(context, _name, returnType, _parameters),
{ MethodReference: MethodDefinition md } => md,
_ => throw new NotSupportedException($"Function {_name} already defined as immutable.")
};
Expand Down
10 changes: 6 additions & 4 deletions Cesium.CodeGen/Ir/TopLevel/TopLevelDeclaration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,10 @@ private static void EmitFunctionDeclaration(
return;
}

var typeSystem = context.TypeSystem;
var method = context.ModuleType.DefineMethod(
typeSystem,
context,
identifier,
returnType.Resolve(typeSystem),
returnType.Resolve(context),
parametersInfo);

context.Functions.Add(identifier, new FunctionInfo(parametersInfo, returnType, method));
Expand All @@ -128,7 +127,10 @@ private static void EmitTypeDef(TranslationUnitContext context, TypeDefDeclarati
if (cliImportMemberName != null)
throw new NotSupportedException($"typedef for CLI import not supported: {cliImportMemberName}.");

context.Types.Add(identifier, type.Resolve(context.TypeSystem));
if (type is INamedType t)
context.GenerateType(t, identifier);
else
throw new NotSupportedException($"Not supported type generation for type {type}.");
}
}
}
3 changes: 2 additions & 1 deletion Cesium.CodeGen/Ir/Types/ConstType.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
using Cesium.CodeGen.Contexts;
using Mono.Cecil;

namespace Cesium.CodeGen.Ir.Types;

internal record ConstType(IType Base) : IType
{
public TypeReference Resolve(TypeSystem typeSystem) => Base.Resolve(typeSystem);
public TypeReference Resolve(TranslationUnitContext context) => Base.Resolve(context);
}
9 changes: 9 additions & 0 deletions Cesium.CodeGen/Ir/Types/INamedType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using Cesium.CodeGen.Contexts;
using Mono.Cecil;

namespace Cesium.CodeGen.Ir.Types;

internal interface INamedType
{
TypeDefinition Emit(string name, TranslationUnitContext context);
}
3 changes: 2 additions & 1 deletion Cesium.CodeGen/Ir/Types/IType.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
using Cesium.CodeGen.Contexts;
using Mono.Cecil;

namespace Cesium.CodeGen.Ir.Types;

internal interface IType
{
TypeReference Resolve(TypeSystem typeSystem);
TypeReference Resolve(TranslationUnitContext context);
}
3 changes: 2 additions & 1 deletion Cesium.CodeGen/Ir/Types/PointerType.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
using Cesium.CodeGen.Contexts;
using Mono.Cecil;
using Mono.Cecil.Rocks;

namespace Cesium.CodeGen.Ir.Types;

internal record PointerType(IType Base) : IType
{
public TypeReference Resolve(TypeSystem typeSystem) => Base.Resolve(typeSystem).MakePointerType();
public TypeReference Resolve(TranslationUnitContext context) => Base.Resolve(context).MakePointerType();
}
17 changes: 11 additions & 6 deletions Cesium.CodeGen/Ir/Types/PrimitiveType.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Cesium.CodeGen.Contexts;
using Mono.Cecil;

namespace Cesium.CodeGen.Ir.Types;
Expand All @@ -11,11 +12,15 @@ internal enum PrimitiveTypeKind

internal record PrimitiveType(PrimitiveTypeKind Kind) : IType
{
public TypeReference Resolve(TypeSystem typeSystem) => Kind switch
public TypeReference Resolve(TranslationUnitContext context)
{
PrimitiveTypeKind.Char => typeSystem.Byte,
PrimitiveTypeKind.Int => typeSystem.Int32,
PrimitiveTypeKind.Void => typeSystem.Void,
_ => throw new NotImplementedException($"Primitive type not supported, yet: {this}.")
};
var typeSystem = context.TypeSystem;
return Kind switch
{
PrimitiveTypeKind.Char => typeSystem.Byte,
PrimitiveTypeKind.Int => typeSystem.Int32,
PrimitiveTypeKind.Void => typeSystem.Void,
_ => throw new NotImplementedException($"Primitive type not supported, yet: {this}.")
};
}
}
47 changes: 42 additions & 5 deletions Cesium.CodeGen/Ir/Types/StructType.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,51 @@
using Cesium.Ast;
using Cesium.CodeGen.Contexts;
using Cesium.CodeGen.Ir.Declarations;
using Mono.Cecil;

namespace Cesium.CodeGen.Ir.Types;

public class StructType : IType
internal class StructType : IType, INamedType
{
public StructType(IEnumerable<StructDeclaration> declarations)
private readonly IEnumerable<LocalDeclarationInfo> _members;
public StructType(IEnumerable<LocalDeclarationInfo> members)
{
_members = members;
}

public TypeReference Resolve(TypeSystem typeSystem) =>
throw new NotImplementedException();
public TypeDefinition Emit(string name, TranslationUnitContext context)
{
var structType = new TypeDefinition(
"",
name,
TypeAttributes.Sealed,
context.Module.ImportReference(typeof(ValueType)));
context.Module.Types.Add(structType);

foreach (var member in _members)
{
var (type, identifier, parametersInfo, cliImportMemberName) = member;
if (identifier == null)
throw new NotImplementedException(
$"Anonymous struct members for {name} aren't supported, yet: {type}.");

if (parametersInfo != null)
throw new NotImplementedException(
$"Functional struct members for {name} aren't supported, yet: {identifier}.");

if (cliImportMemberName != null)
throw new NotSupportedException(
$"CLI imports inside struct members aren't supported: {cliImportMemberName}.");

structType.Fields.Add(
new FieldDefinition(
identifier,
FieldAttributes.Public,
type.Resolve(context)));
}

return structType;
}

public TypeReference Resolve(TranslationUnitContext context) =>
context.GetTypeReference(this) ?? throw new NotSupportedException($"Type {this} was not found.");
}

0 comments on commit a586b1a

Please sign in to comment.