Interfaces working?
This commit is contained in:
@@ -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()
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user