diff --git a/example/src/main.nub b/example/src/main.nub index 2f0975f..173fc0f 100644 --- a/example/src/main.nub +++ b/example/src/main.nub @@ -1,6 +1,11 @@ extern func puts(text: cstring) -struct Human +interface Test +{ + func print() +} + +struct Human : Test { name: cstring @@ -12,7 +17,7 @@ struct Human func main(args: []cstring): i64 { - let human = alloc Human { + let human: Test = alloc Human { name = "oliver" } diff --git a/src/compiler/NubLang/Generation/QBE/QBEGenerator.Expression.cs b/src/compiler/NubLang/Generation/QBE/QBEGenerator.Expression.cs index 9c0252c..161db2a 100644 --- a/src/compiler/NubLang/Generation/QBE/QBEGenerator.Expression.cs +++ b/src/compiler/NubLang/Generation/QBE/QBEGenerator.Expression.cs @@ -424,7 +424,7 @@ public partial class QBEGenerator private Val EmitStructFuncCall(StructFuncCallNode structFuncCall) { var expression = EmitExpression(structFuncCall.Expression); - var thisParameter = EmitUnwrap(EmitExpression(structFuncCall.ThisParam)); + var thisParameter = EmitUnwrap(EmitExpression(structFuncCall.StructExpression)); List parameterStrings = [$"l {thisParameter}"]; @@ -470,7 +470,32 @@ public partial class QBEGenerator private Val EmitInterfaceFuncCall(InterfaceFuncCallNode interfaceFuncCall) { - throw new NotImplementedException(); + var expression = EmitExpression(interfaceFuncCall.Expression); + + var thisParameter = EmitUnwrap(EmitExpression(interfaceFuncCall.InterfaceExpression)); + _writer.Indented($"{thisParameter} =l add {thisParameter}, 8"); + _writer.Indented($"{thisParameter} =l loadl {thisParameter}"); + + List parameterStrings = [$"l {thisParameter}"]; + + foreach (var parameter in interfaceFuncCall.Parameters) + { + var copy = EmitCreateCopyOrInitialize(parameter); + parameterStrings.Add($"{FuncQBETypeName(parameter.Type)} {copy}"); + } + + var funcPointer = EmitUnwrap(expression); + if (interfaceFuncCall.Type is VoidTypeNode) + { + _writer.Indented($"call {funcPointer}({string.Join(", ", parameterStrings)})"); + return new Val(string.Empty, interfaceFuncCall.Type, ValKind.Direct); + } + else + { + var outputName = TmpName(); + _writer.Indented($"{outputName} {QBEAssign(interfaceFuncCall.Type)} call {funcPointer}({string.Join(", ", parameterStrings)})"); + return new Val(outputName, interfaceFuncCall.Type, ValKind.Direct); + } } private Val EmitInterfaceInitializer(InterfaceInitializerNode interfaceInitializer, string? destination = null) diff --git a/src/compiler/NubLang/Generation/QBE/QBEGenerator.cs b/src/compiler/NubLang/Generation/QBE/QBEGenerator.cs index 983174c..92bcfd0 100644 --- a/src/compiler/NubLang/Generation/QBE/QBEGenerator.cs +++ b/src/compiler/NubLang/Generation/QBE/QBEGenerator.cs @@ -269,6 +269,7 @@ public partial class QBEGenerator { case ArrayInitializerNode: case StructInitializerNode: + case InterfaceInitializerNode: case LiteralNode { Kind: LiteralKind.String }: { destination = EmitUnwrap(EmitExpression(source)); @@ -282,7 +283,7 @@ public partial class QBEGenerator private string EmitCreateCopyOrInitialize(ExpressionNode source) { - // If the source is a value which is not used yet such as an array/struct initializer or literal, we can skip copying + // If the source is a value which is not used yet such as an array/struct/interface initializer or literal, we can skip copying if (EmitTryCreateWithoutCopy(source, out var uncopiedValue)) { return uncopiedValue; diff --git a/src/compiler/NubLang/TypeChecking/Node/ExpressionNode.cs b/src/compiler/NubLang/TypeChecking/Node/ExpressionNode.cs index 6869f7b..9fc17fe 100644 --- a/src/compiler/NubLang/TypeChecking/Node/ExpressionNode.cs +++ b/src/compiler/NubLang/TypeChecking/Node/ExpressionNode.cs @@ -30,9 +30,9 @@ public record UnaryExpressionNode(TypeNode Type, UnaryOperator Operator, Express public record FuncCallNode(TypeNode Type, ExpressionNode Expression, IReadOnlyList Parameters) : ExpressionNode(Type); -public record StructFuncCallNode(TypeNode Type, ExpressionNode Expression, ExpressionNode ThisParam, IReadOnlyList Parameters) : ExpressionNode(Type); +public record StructFuncCallNode(TypeNode Type, ExpressionNode Expression, ExpressionNode StructExpression, IReadOnlyList Parameters) : ExpressionNode(Type); -public record InterfaceFuncCallNode(TypeNode Type, ExpressionNode Expression, ExpressionNode ThisParam, IReadOnlyList Parameters) : ExpressionNode(Type); +public record InterfaceFuncCallNode(TypeNode Type, ExpressionNode Expression, ExpressionNode InterfaceExpression, IReadOnlyList Parameters) : ExpressionNode(Type); public record VariableIdentNode(TypeNode Type, string Name) : ExpressionNode(Type);