Skip to content

Commit

Permalink
(#72) IR: better architecture to support typedef
Browse files Browse the repository at this point in the history
  • Loading branch information
ForNeVeR committed Feb 16, 2022
1 parent 440b74e commit ee70a14
Show file tree
Hide file tree
Showing 12 changed files with 266 additions and 65 deletions.
3 changes: 3 additions & 0 deletions Cesium.CodeGen.Tests/CodeGenTypeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,7 @@ public Task EmptyFunctionDeclaration() => DoTest(@"
void foo(void)
{
}");

[Fact]
public Task EmptyStructDefinition() => DoTest("typedef struct { int x; } foo;");
}
3 changes: 1 addition & 2 deletions Cesium.CodeGen/Extensions/TranslationUnitEx.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using Cesium.Ast;
using Cesium.CodeGen.Ir.TopLevel;
using FunctionDefinition = Cesium.CodeGen.Ir.TopLevel.FunctionDefinition;
using SymbolDeclaration = Cesium.CodeGen.Ir.TopLevel.SymbolDeclaration;

namespace Cesium.CodeGen.Extensions;

Expand All @@ -11,7 +10,7 @@ public static IEnumerable<ITopLevelNode> ToIntermediate(this TranslationUnit tra
translationUnit.Declarations.Select(x => (ITopLevelNode)(x switch
{
Ast.FunctionDefinition func => new FunctionDefinition(func),
Ast.SymbolDeclaration sym => new SymbolDeclaration(sym),
Ast.SymbolDeclaration sym => new TopLevelDeclaration(sym),
_ => throw new NotImplementedException($"Declaration not supported: {x}.")
}));
}
60 changes: 46 additions & 14 deletions Cesium.CodeGen/Ir/BlockItems/DeclarationBlockItem.cs
Original file line number Diff line number Diff line change
@@ -1,36 +1,65 @@
using Cesium.Ast;
using Cesium.CodeGen.Contexts;
using Cesium.CodeGen.Extensions;
using Cesium.CodeGen.Ir.Declarations;
using Mono.Cecil.Cil;

namespace Cesium.CodeGen.Ir.BlockItems;

internal class DeclarationBlockItem : IBlockItem
{
private readonly IList<InitializableDeclarationInfo> _declarations;
private DeclarationBlockItem(IList<InitializableDeclarationInfo> declarations)
private readonly IScopedDeclarationInfo _declaration;
private DeclarationBlockItem(IScopedDeclarationInfo declaration)
{
_declarations = declarations;
_declaration = declaration;
}

public DeclarationBlockItem(Declaration declaration)
: this(InitializableDeclarationInfo.Of(declaration).ToList())
: this(IScopedDeclarationInfo.Of(declaration))
{
}

public IBlockItem Lower() =>
new DeclarationBlockItem(
_declarations
.Select(d =>
{
var (declaration, initializer) = d;
return new InitializableDeclarationInfo(declaration, initializer?.Lower());
})
.ToList());
public IBlockItem Lower()
{
switch (_declaration)
{
case ScopedIdentifierDeclaration declaration:
{
declaration.Deconstruct(out var items);
return new DeclarationBlockItem(
new ScopedIdentifierDeclaration(
items.Select(d =>
{
var (itemDeclaration, initializer) = d;
return new InitializableDeclarationInfo(itemDeclaration, initializer?.Lower());
})
.ToList()));
}
case TypeDefDeclaration _: return this;
default: throw new ArgumentOutOfRangeException(nameof(_declaration));
}
}


public void EmitTo(FunctionScope scope)
{
foreach (var (declaration, initializer) in _declarations)
switch (_declaration)
{
case ScopedIdentifierDeclaration declaration:
EmitScopedIdentifier(scope, declaration);
break;
case TypeDefDeclaration declaration:
EmitTypeDef(declaration);
break;
default:
throw new ArgumentOutOfRangeException(nameof(_declaration));
}
}

private static void EmitScopedIdentifier(FunctionScope scope, ScopedIdentifierDeclaration scopedDeclaration)
{
scopedDeclaration.Deconstruct(out var declarations);
foreach (var (declaration, initializer) in declarations)
{
var method = scope.Method;
var (type, identifier, parametersInfo, cliImportMemberName) = declaration;
Expand Down Expand Up @@ -59,4 +88,7 @@ public void EmitTo(FunctionScope scope)
scope.StLoc(variable);
}
}

private static void EmitTypeDef(TypeDefDeclaration declaration) =>
throw new NotImplementedException($"typedef is not supported at block level, yet: {declaration}.");
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
using Cesium.Ast;
using Cesium.CodeGen.Ir.Types;

namespace Cesium.CodeGen.Ir;

internal record DeclarationInfo(
IType ReturnType,
namespace Cesium.CodeGen.Ir.Declarations;

/// <summary>
/// A local declaration info, as opposed to <see cref="IScopedDeclarationInfo"/>, cannot be a typedef or have an
/// initializer, and is always a part of a more complex syntax construct: say, a parameter declaration or a function
/// definition.
/// </summary>
internal record LocalDeclarationInfo(
IType Type,
string? Identifier,
ParametersInfo? Parameters,
string? CliImportMemberName)
{
public static DeclarationInfo Of(IList<IDeclarationSpecifier> specifiers, Declarator? declarator)
public static LocalDeclarationInfo Of(IList<IDeclarationSpecifier> specifiers, Declarator? declarator)
{
var (type, cliImportMemberName) = GetPrimitiveInfo(specifiers);
var (type, cliImportMemberName) = ProcessSpecifiers(specifiers);
if (declarator == null)
return new DeclarationInfo(type, null, null, null);
return new LocalDeclarationInfo(type, null, null, null);

var (pointer, directDeclarator) = declarator;
if (pointer != null)
Expand Down Expand Up @@ -76,13 +81,13 @@ public static DeclarationInfo Of(IList<IDeclarationSpecifier> specifiers, Declar
currentDirectDeclarator = currentDirectDeclarator.Base;
}

return new DeclarationInfo(type, identifier, parameters, cliImportMemberName);
return new LocalDeclarationInfo(type, identifier, parameters, cliImportMemberName);
}

private static (IType, string? cliImportMemberName) GetPrimitiveInfo(
private static (IType, string? cliImportMemberName) ProcessSpecifiers(
IList<IDeclarationSpecifier> specifiers)
{
PrimitiveType? type = null;
IType? type = null;
var isConst = false;
string? cliImportMemberName = null;
foreach (var specifier in specifiers)
Expand Down Expand Up @@ -127,6 +132,26 @@ private static (IType, string? cliImportMemberName) GetPrimitiveInfo(
cliImportMemberName = cis.MemberName;
break;

case StorageClassSpecifier { Name: "typedef" }:
throw new NotSupportedException($"typedef not expected: {string.Join(", ", specifiers)}.");

case StructOrUnionSpecifier typeSpecifier:
{
if (type != null)
throw new NotSupportedException(
$"Cannot update type {type} with a struct specifier {typeSpecifier}.");

var (complexTypeKind, identifier, structDeclarations) = typeSpecifier;
if (complexTypeKind != ComplexTypeKind.Struct)
throw new NotImplementedException($"Complex type kind not supported, yet: {complexTypeKind}.");

if (identifier != null)
throw new NotImplementedException($"Named structures aren't supported, yet: {identifier}.");

type = new StructType(structDeclarations);
break;
}

default:
throw new NotImplementedException($"Declaration specifier {specifier} isn't supported, yet.");
}
Expand Down
57 changes: 57 additions & 0 deletions Cesium.CodeGen/Ir/Declarations/ScopedDeclarationInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using Cesium.Ast;
using Cesium.CodeGen.Extensions;
using Cesium.CodeGen.Ir.Expressions;

namespace Cesium.CodeGen.Ir.Declarations;

/// <summary>
/// A scoped declaration info is either a top-level declaration (at the level of the translation unit), or a block-level
/// declaration. Both of them have their scope, and may declare types (typedef).
/// </summary>
internal interface IScopedDeclarationInfo
{
public static IScopedDeclarationInfo Of(Declaration declaration)
{
var (specifiers, initDeclarators) = declaration;
if (initDeclarators == null)
throw new NotSupportedException($"Symbol declaration has no init declarators: {declaration}.");

if (specifiers.Length > 0 && specifiers[0] is StorageClassSpecifier { Name: "typedef" })
{
return TypeDefDeclaration.Of(specifiers.Skip(1), initDeclarators);
}

var initializableDeclarations = initDeclarators
.Select<InitDeclarator, InitializableDeclarationInfo>(id => Of(specifiers, id))
.ToList();

return new ScopedIdentifierDeclaration(initializableDeclarations);
}

private static InitializableDeclarationInfo Of(
IList<IDeclarationSpecifier> specifiers,
InitDeclarator initDeclarator)
{
var (declarator, initializer) = initDeclarator;
var declarationInfo = LocalDeclarationInfo.Of(specifiers, declarator);
var expression = initializer switch
{
null => null,
AssignmentInitializer ai => ai.Expression.ToIntermediate(),
_ => throw new NotImplementedException($"Object initializer not supported, yet: {initializer}.")
};
return new InitializableDeclarationInfo(declarationInfo, expression);
}
}

internal record TypeDefDeclaration : IScopedDeclarationInfo
{
internal static TypeDefDeclaration Of(
IEnumerable<IDeclarationSpecifier> specifiers,
IEnumerable<InitDeclarator> initDeclarators)
{
throw new NotSupportedException("typedef not supported, yet.");
}
}
internal record ScopedIdentifierDeclaration(ICollection<InitializableDeclarationInfo> Items) : IScopedDeclarationInfo;
internal record InitializableDeclarationInfo(LocalDeclarationInfo Declaration, IExpression? Initializer);
32 changes: 0 additions & 32 deletions Cesium.CodeGen/Ir/InitializableDeclarationInfo.cs

This file was deleted.

3 changes: 2 additions & 1 deletion Cesium.CodeGen/Ir/ParametersInfo.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Cesium.Ast;
using Cesium.CodeGen.Ir.Declarations;
using Cesium.CodeGen.Ir.Types;

namespace Cesium.CodeGen.Ir;
Expand Down Expand Up @@ -45,7 +46,7 @@ public static ParameterInfo Of(ParameterDeclaration declaration)
throw new NotImplementedException(
$"Parameter with abstract declarator is not supported, yet: {declaration}.");

var (type, identifier, parameters, cliImportMemberName) = DeclarationInfo.Of(specifiers, declarator);
var (type, identifier, parameters, cliImportMemberName) = LocalDeclarationInfo.Of(specifiers, declarator);

if (parameters != null)
throw new NotImplementedException($"Parameters with parameters are not supported, yet: {parameters}.");
Expand Down
3 changes: 2 additions & 1 deletion Cesium.CodeGen/Ir/TopLevel/FunctionDefinition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using Cesium.CodeGen.Contexts.Meta;
using Cesium.CodeGen.Extensions;
using Cesium.CodeGen.Ir.BlockItems;
using Cesium.CodeGen.Ir.Declarations;
using Cesium.CodeGen.Ir.Types;
using Cesium.Runtime;
using Mono.Cecil;
Expand All @@ -27,7 +28,7 @@ public FunctionDefinition(Ast.FunctionDefinition function)
{
var (specifiers, declarator, declarations, astStatement) = function;
(_returnType, var name, _parameters, var cliImportMemberName) =
DeclarationInfo.Of(specifiers, declarator);
LocalDeclarationInfo.Of(specifiers, declarator);
_name = name ?? throw new NotSupportedException($"Function without name: {function}.");

if (declarations?.IsEmpty == false)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,42 @@
using Cesium.CodeGen.Contexts;
using Cesium.CodeGen.Contexts.Meta;
using Cesium.CodeGen.Extensions;
using Cesium.CodeGen.Ir.Declarations;
using Cesium.CodeGen.Ir.Types;

namespace Cesium.CodeGen.Ir.TopLevel;

internal class SymbolDeclaration : ITopLevelNode
internal class TopLevelDeclaration : ITopLevelNode
{
private readonly IList<InitializableDeclarationInfo> _declarations;
public SymbolDeclaration(Ast.SymbolDeclaration ast)
private readonly IScopedDeclarationInfo _declaration;
public TopLevelDeclaration(Ast.SymbolDeclaration ast)
{
ast.Deconstruct(out var declaration);
_declarations = InitializableDeclarationInfo.Of(declaration).ToList();
_declaration = IScopedDeclarationInfo.Of(declaration);
}

public void EmitTo(TranslationUnitContext context)
{
foreach (var (declaration, initializer) in _declarations)
switch (_declaration)
{
case ScopedIdentifierDeclaration declaration:
EmitScopedIdentifier(context, declaration);
break;
case TypeDefDeclaration declaration:
EmitTypeDef(declaration);
break;
default:
throw new ArgumentOutOfRangeException(nameof(_declaration));
}
}

private static void EmitScopedIdentifier(
TranslationUnitContext context,
ScopedIdentifierDeclaration scopedDeclaration)
{
scopedDeclaration.Deconstruct(out var items);

foreach (var (declaration, initializer) in items)
{
var (type, identifier, parametersInfo, cliImportMemberName) = declaration;
if (identifier == null)
Expand Down Expand Up @@ -92,4 +112,7 @@ private static void EmitFunctionDeclaration(

context.Functions.Add(identifier, new FunctionInfo(parametersInfo, returnType, method));
}

private static void EmitTypeDef(TypeDefDeclaration declaration) =>
throw new NotImplementedException($"typedef is not supported at block level, yet: {declaration}.");
}
14 changes: 14 additions & 0 deletions Cesium.CodeGen/Ir/Types/StructType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using Cesium.Ast;
using Mono.Cecil;

namespace Cesium.CodeGen.Ir.Types;

public class StructType : IType
{
public StructType(IEnumerable<StructDeclaration> declarations)
{
}

public TypeReference Resolve(TypeSystem typeSystem) =>
throw new NotImplementedException();
}
Loading

0 comments on commit ee70a14

Please sign in to comment.