Interfaces working?

This commit is contained in:
nub31
2025-08-13 00:41:28 +02:00
parent fc5b08e5c6
commit c8f913dc23
5 changed files with 119 additions and 58 deletions

View File

@@ -1,27 +1,32 @@
extern func puts(fmt: cstring)
interface Printable
{
func print()
}
struct Human : Printable {
struct Human : Printable
{
name: cstring
func print_name()
{
puts(this^.name)
}
func print()
{
puts("example")
puts(this^.name)
}
}
func main(args: []cstring): i64
{
let human: Human = alloc Human {
let human = alloc Human {
name = "oliver"
}
human.print()
print_printable(human)
return 0
}
func print_printable(printable: Printable)
{
printable.print()
}

View File

@@ -19,6 +19,7 @@ public partial class QBEGenerator
BinaryExpressionNode binaryExpression => EmitBinaryExpression(binaryExpression),
FuncCallNode funcCallExpression => EmitFuncCall(funcCallExpression),
InterfaceFuncAccessNode interfaceFuncAccess => EmitInterfaceFuncAccess(interfaceFuncAccess),
InterfaceInitializerNode interfaceInitializer => EmitInterfaceInitializer(interfaceInitializer),
ExternFuncIdentNode externFuncIdent => EmitExternFuncIdent(externFuncIdent),
LocalFuncIdentNode localFuncIdent => EmitLocalFuncIdent(localFuncIdent),
VariableIdentNode variableIdent => EmitVariableIdent(variableIdent),
@@ -329,15 +330,14 @@ public partial class QBEGenerator
{
destination = TmpName();
var size = SizeOf(structInitializer.StructType);
if (structDef.InterfaceImplementations.Any())
{
size += 8;
}
_writer.Indented($"{destination} =l alloc8 {size}");
}
// if (structDef.InterfaceImplementations.Any())
// {
// _writer.Indented($"storel {destination}, {StructVtableName(structDef.Name)}");
// }
foreach (var field in structDef.Fields)
{
if (!structInitializer.Initializers.TryGetValue(field.Name, out var valueExpression))
@@ -424,15 +424,50 @@ public partial class QBEGenerator
private Val EmitStructFuncAccess(StructFuncAccessNode structFuncAccess)
{
var target = EmitExpression(structFuncAccess.Target);
Debug.Assert(target.Kind == ValKind.Pointer);
var structDef = _definitionTable.LookupStruct(structFuncAccess.StructType.Name);
var func = StructFuncName(structDef.Name, structFuncAccess.Func);
return new Val(func, structFuncAccess.Type, ValKind.Direct, target);
return new Val(func, structFuncAccess.Type, ValKind.Direct, target.Name);
}
private Val EmitInterfaceFuncAccess(InterfaceFuncAccessNode interfaceFuncAccess)
{
throw new NotImplementedException();
var target = EmitUnwrap(EmitExpression(interfaceFuncAccess.Target));
var interfaceDef = _definitionTable.LookupInterface(interfaceFuncAccess.InterfaceType.Name);
var functionIndex = interfaceDef.Functions.ToList().FindIndex(x => x.Name == interfaceFuncAccess.FuncName);
var offset = functionIndex * 8;
var vtable = TmpName();
_writer.Indented($"{vtable} =l loadl {target}");
var funcOffset = TmpName();
_writer.Indented($"{funcOffset} =l add {vtable}, {offset}");
var func = TmpName();
_writer.Indented($"{func} =l loadl {funcOffset}");
var data = TmpName();
_writer.Indented($"{data} =l add {target}, 8");
return new Val(func, interfaceFuncAccess.Type, ValKind.Direct, data);
}
private Val EmitInterfaceInitializer(InterfaceInitializerNode interfaceInitializer)
{
var implementation = EmitUnwrap(EmitExpression(interfaceInitializer.Implementation));
var result = TmpName();
_writer.Indented($"{result} =l alloc8 16");
_writer.Indented($"storel {StructVtableName(interfaceInitializer.StructType.Name)}, {result}");
var objectPointer = TmpName();
_writer.Indented($"{objectPointer} =l add {result}, 8");
_writer.Indented($"storel {implementation}, {objectPointer}");
return new Val(result, interfaceInitializer.InterfaceType, ValKind.Direct);
}
private Val EmitFuncCall(FuncCallNode funcCall)
@@ -444,8 +479,7 @@ public partial class QBEGenerator
if (expression.ThisArg != null)
{
Debug.Assert(expression.ThisArg.Kind == ValKind.Pointer);
parameterStrings.Add($"l {expression.ThisArg.Name}");
parameterStrings.Add($"l {expression.ThisArg}");
}
foreach (var parameter in funcCall.Parameters)

View File

@@ -346,11 +346,6 @@ public partial class QBEGenerator
return StructTypeName(structType.Name);
}
if (complexType is InterfaceTypeNode interfaceType)
{
return InterfaceTypeName(interfaceType.Name);
}
return "l";
}
@@ -434,11 +429,6 @@ public partial class QBEGenerator
return StructTypeName(structType.Name);
}
if (complexType is InterfaceTypeNode interfaceType)
{
return InterfaceTypeName(interfaceType.Name);
}
return "l";
}
}
@@ -496,10 +486,10 @@ public partial class QBEGenerator
{
var offset = 0;
if (structType.InterfaceImplementations.Any())
{
offset = 8;
}
// if (structType.InterfaceImplementations.Any())
// {
// offset = 8;
// }
foreach (var field in structType.Fields)
{
@@ -561,10 +551,10 @@ public partial class QBEGenerator
{
var offset = 0;
if (structDef.InterfaceImplementations.Any())
{
offset = 8;
}
// if (structDef.InterfaceImplementations.Any())
// {
// offset = 8;
// }
foreach (var field in structDef.Fields)
{
@@ -619,11 +609,6 @@ public partial class QBEGenerator
return $":{name}";
}
private string InterfaceTypeName(string name)
{
return $":{name}";
}
private string StructFuncName(string structName, string funcName)
{
return $"${structName}_{funcName}";
@@ -649,7 +634,7 @@ public class CStringLiteral(string value, string name)
public string Name { get; } = name;
}
public record Val(string Name, TypeNode Type, ValKind Kind, Val? ThisArg = null);
public record Val(string Name, TypeNode Type, ValKind Kind, string? ThisArg = null);
public class Scope(Scope? parent = null)
{

View File

@@ -55,3 +55,5 @@ public record InterfaceFuncAccessNode(TypeNode Type, InterfaceTypeNode Interface
public record StructInitializerNode(StructTypeNode StructType, Dictionary<string, ExpressionNode> Initializers) : ExpressionNode(StructType);
public record DereferenceNode(TypeNode Type, ExpressionNode Expression) : ExpressionNode(Type);
public record InterfaceInitializerNode(TypeNode Type, InterfaceTypeNode InterfaceType, StructTypeNode StructType, ExpressionNode Implementation) : ExpressionNode(Type);

View File

@@ -204,22 +204,36 @@ public sealed class TypeChecker
{
TypeNode? type = null;
var assignment = Optional<ExpressionNode>.Empty();
if (statement.Assignment.HasValue)
{
var boundValue = CheckExpression(statement.Assignment.Value, type);
assignment = boundValue;
type = boundValue.Type;
}
if (statement.ExplicitType.HasValue)
{
type = CheckType(statement.ExplicitType.Value);
}
var assignment = Optional<ExpressionNode>.Empty();
if (statement.Assignment.HasValue)
{
var boundValue = CheckExpression(statement.Assignment.Value, type);
assignment = boundValue;
if (type != null)
{
if (boundValue.Type != type)
{
throw new TypeCheckerException(Diagnostic.Error($"{boundValue.Type} is not assignable to {type}").Build());
}
}
else
{
if (type == null)
{
type = boundValue.Type;
}
}
}
if (type == null)
{
throw new NotImplementedException("Diagnostics not implemented");
throw new TypeCheckerException(Diagnostic.Error($"Unknown type of variable {statement.Name}").Build());
}
Scope.Declare(new Variable(statement.Name, type));
@@ -234,7 +248,7 @@ public sealed class TypeChecker
private ExpressionNode CheckExpression(ExpressionSyntax node, TypeNode? expectedType = null)
{
return node switch
var result = node switch
{
AddressOfSyntax expression => CheckAddressOf(expression),
ArrowFuncSyntax expression => CheckArrowFunc(expression, expectedType),
@@ -250,6 +264,27 @@ public sealed class TypeChecker
UnaryExpressionSyntax expression => CheckUnaryExpression(expression),
_ => throw new ArgumentOutOfRangeException(nameof(node))
};
if (expectedType != null && result.Type != expectedType)
{
return CheckConversion(expectedType, result);
}
return result;
}
private ExpressionNode CheckConversion(TypeNode targetType, ExpressionNode expression)
{
// todo(nub): Add conversions for primitive types such as i32 -> i64 etc.
switch (expression.Type)
{
case StructTypeNode structType when targetType is InterfaceTypeNode interfaceType:
{
return new InterfaceInitializerNode(interfaceType, interfaceType, structType, expression);
}
}
throw new TypeCheckerException(Diagnostic.Error($"Cannot convert {expression.Type} to {targetType}").Build());
}
private AddressOfNode CheckAddressOf(AddressOfSyntax expression)
@@ -401,14 +436,14 @@ public sealed class TypeChecker
{
var boundExpression = CheckExpression(expression.Target);
if (boundExpression.Type is InterfaceTypeNode customType)
if (boundExpression.Type is InterfaceTypeNode interfaceType)
{
var interfaces = _definitionTable.LookupInterface(customType.Name).ToArray();
var interfaces = _definitionTable.LookupInterface(interfaceType.Name).ToArray();
if (interfaces.Length > 0)
{
if (interfaces.Length > 1)
{
throw new TypeCheckerException(Diagnostic.Error($"Interface {customType} has multiple definitions").Build());
throw new TypeCheckerException(Diagnostic.Error($"Interface {interfaceType} has multiple definitions").Build());
}
var @interface = interfaces[0];
@@ -418,7 +453,7 @@ public sealed class TypeChecker
{
if (interfaceFuncs.Length > 1)
{
throw new TypeCheckerException(Diagnostic.Error($"Interface {customType} has multiple functions with the name {expression.Member}").Build());
throw new TypeCheckerException(Diagnostic.Error($"Interface {interfaceType} has multiple functions with the name {expression.Member}").Build());
}
var interfaceFunc = interfaceFuncs[0];
@@ -426,7 +461,7 @@ public sealed class TypeChecker
var returnType = CheckType(interfaceFunc.Signature.ReturnType);
var parameterTypes = interfaceFunc.Signature.Parameters.Select(p => CheckType(p.Type)).ToList();
var type = new FuncTypeNode(parameterTypes, returnType);
return new InterfaceFuncAccessNode(type, customType, boundExpression, expression.Member);
return new InterfaceFuncAccessNode(type, interfaceType, boundExpression, expression.Member);
}
}
}