Interfaces working?
This commit is contained in:
@@ -1,27 +1,32 @@
|
|||||||
|
extern func puts(fmt: cstring)
|
||||||
|
|
||||||
interface Printable
|
interface Printable
|
||||||
{
|
{
|
||||||
func print()
|
func print()
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Human : Printable {
|
struct Human : Printable
|
||||||
|
{
|
||||||
name: cstring
|
name: cstring
|
||||||
|
|
||||||
func print_name()
|
|
||||||
{
|
|
||||||
puts(this^.name)
|
|
||||||
}
|
|
||||||
|
|
||||||
func print()
|
func print()
|
||||||
{
|
{
|
||||||
puts("example")
|
puts(this^.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func main(args: []cstring): i64
|
func main(args: []cstring): i64
|
||||||
{
|
{
|
||||||
let human: Human = alloc Human {
|
let human = alloc Human {
|
||||||
name = "oliver"
|
name = "oliver"
|
||||||
}
|
}
|
||||||
|
|
||||||
human.print()
|
human.print()
|
||||||
|
print_printable(human)
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func print_printable(printable: Printable)
|
||||||
|
{
|
||||||
|
printable.print()
|
||||||
|
}
|
||||||
@@ -19,6 +19,7 @@ public partial class QBEGenerator
|
|||||||
BinaryExpressionNode binaryExpression => EmitBinaryExpression(binaryExpression),
|
BinaryExpressionNode binaryExpression => EmitBinaryExpression(binaryExpression),
|
||||||
FuncCallNode funcCallExpression => EmitFuncCall(funcCallExpression),
|
FuncCallNode funcCallExpression => EmitFuncCall(funcCallExpression),
|
||||||
InterfaceFuncAccessNode interfaceFuncAccess => EmitInterfaceFuncAccess(interfaceFuncAccess),
|
InterfaceFuncAccessNode interfaceFuncAccess => EmitInterfaceFuncAccess(interfaceFuncAccess),
|
||||||
|
InterfaceInitializerNode interfaceInitializer => EmitInterfaceInitializer(interfaceInitializer),
|
||||||
ExternFuncIdentNode externFuncIdent => EmitExternFuncIdent(externFuncIdent),
|
ExternFuncIdentNode externFuncIdent => EmitExternFuncIdent(externFuncIdent),
|
||||||
LocalFuncIdentNode localFuncIdent => EmitLocalFuncIdent(localFuncIdent),
|
LocalFuncIdentNode localFuncIdent => EmitLocalFuncIdent(localFuncIdent),
|
||||||
VariableIdentNode variableIdent => EmitVariableIdent(variableIdent),
|
VariableIdentNode variableIdent => EmitVariableIdent(variableIdent),
|
||||||
@@ -329,15 +330,14 @@ public partial class QBEGenerator
|
|||||||
{
|
{
|
||||||
destination = TmpName();
|
destination = TmpName();
|
||||||
var size = SizeOf(structInitializer.StructType);
|
var size = SizeOf(structInitializer.StructType);
|
||||||
|
|
||||||
if (structDef.InterfaceImplementations.Any())
|
|
||||||
{
|
|
||||||
size += 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
_writer.Indented($"{destination} =l alloc8 {size}");
|
_writer.Indented($"{destination} =l alloc8 {size}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if (structDef.InterfaceImplementations.Any())
|
||||||
|
// {
|
||||||
|
// _writer.Indented($"storel {destination}, {StructVtableName(structDef.Name)}");
|
||||||
|
// }
|
||||||
|
|
||||||
foreach (var field in structDef.Fields)
|
foreach (var field in structDef.Fields)
|
||||||
{
|
{
|
||||||
if (!structInitializer.Initializers.TryGetValue(field.Name, out var valueExpression))
|
if (!structInitializer.Initializers.TryGetValue(field.Name, out var valueExpression))
|
||||||
@@ -424,15 +424,50 @@ public partial class QBEGenerator
|
|||||||
private Val EmitStructFuncAccess(StructFuncAccessNode structFuncAccess)
|
private Val EmitStructFuncAccess(StructFuncAccessNode structFuncAccess)
|
||||||
{
|
{
|
||||||
var target = EmitExpression(structFuncAccess.Target);
|
var target = EmitExpression(structFuncAccess.Target);
|
||||||
|
Debug.Assert(target.Kind == ValKind.Pointer);
|
||||||
|
|
||||||
var structDef = _definitionTable.LookupStruct(structFuncAccess.StructType.Name);
|
var structDef = _definitionTable.LookupStruct(structFuncAccess.StructType.Name);
|
||||||
var func = StructFuncName(structDef.Name, structFuncAccess.Func);
|
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)
|
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)
|
private Val EmitFuncCall(FuncCallNode funcCall)
|
||||||
@@ -444,8 +479,7 @@ public partial class QBEGenerator
|
|||||||
|
|
||||||
if (expression.ThisArg != null)
|
if (expression.ThisArg != null)
|
||||||
{
|
{
|
||||||
Debug.Assert(expression.ThisArg.Kind == ValKind.Pointer);
|
parameterStrings.Add($"l {expression.ThisArg}");
|
||||||
parameterStrings.Add($"l {expression.ThisArg.Name}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var parameter in funcCall.Parameters)
|
foreach (var parameter in funcCall.Parameters)
|
||||||
|
|||||||
@@ -346,11 +346,6 @@ public partial class QBEGenerator
|
|||||||
return StructTypeName(structType.Name);
|
return StructTypeName(structType.Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (complexType is InterfaceTypeNode interfaceType)
|
|
||||||
{
|
|
||||||
return InterfaceTypeName(interfaceType.Name);
|
|
||||||
}
|
|
||||||
|
|
||||||
return "l";
|
return "l";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -434,11 +429,6 @@ public partial class QBEGenerator
|
|||||||
return StructTypeName(structType.Name);
|
return StructTypeName(structType.Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (complexType is InterfaceTypeNode interfaceType)
|
|
||||||
{
|
|
||||||
return InterfaceTypeName(interfaceType.Name);
|
|
||||||
}
|
|
||||||
|
|
||||||
return "l";
|
return "l";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -496,10 +486,10 @@ public partial class QBEGenerator
|
|||||||
{
|
{
|
||||||
var offset = 0;
|
var offset = 0;
|
||||||
|
|
||||||
if (structType.InterfaceImplementations.Any())
|
// if (structType.InterfaceImplementations.Any())
|
||||||
{
|
// {
|
||||||
offset = 8;
|
// offset = 8;
|
||||||
}
|
// }
|
||||||
|
|
||||||
foreach (var field in structType.Fields)
|
foreach (var field in structType.Fields)
|
||||||
{
|
{
|
||||||
@@ -561,10 +551,10 @@ public partial class QBEGenerator
|
|||||||
{
|
{
|
||||||
var offset = 0;
|
var offset = 0;
|
||||||
|
|
||||||
if (structDef.InterfaceImplementations.Any())
|
// if (structDef.InterfaceImplementations.Any())
|
||||||
{
|
// {
|
||||||
offset = 8;
|
// offset = 8;
|
||||||
}
|
// }
|
||||||
|
|
||||||
foreach (var field in structDef.Fields)
|
foreach (var field in structDef.Fields)
|
||||||
{
|
{
|
||||||
@@ -619,11 +609,6 @@ public partial class QBEGenerator
|
|||||||
return $":{name}";
|
return $":{name}";
|
||||||
}
|
}
|
||||||
|
|
||||||
private string InterfaceTypeName(string name)
|
|
||||||
{
|
|
||||||
return $":{name}";
|
|
||||||
}
|
|
||||||
|
|
||||||
private string StructFuncName(string structName, string funcName)
|
private string StructFuncName(string structName, string funcName)
|
||||||
{
|
{
|
||||||
return $"${structName}_{funcName}";
|
return $"${structName}_{funcName}";
|
||||||
@@ -649,7 +634,7 @@ public class CStringLiteral(string value, string name)
|
|||||||
public string Name { get; } = 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)
|
public class Scope(Scope? parent = null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -54,4 +54,6 @@ public record InterfaceFuncAccessNode(TypeNode Type, InterfaceTypeNode Interface
|
|||||||
|
|
||||||
public record StructInitializerNode(StructTypeNode StructType, Dictionary<string, ExpressionNode> Initializers) : ExpressionNode(StructType);
|
public record StructInitializerNode(StructTypeNode StructType, Dictionary<string, ExpressionNode> Initializers) : ExpressionNode(StructType);
|
||||||
|
|
||||||
public record DereferenceNode(TypeNode Type, ExpressionNode Expression) : ExpressionNode(Type);
|
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;
|
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)
|
if (statement.ExplicitType.HasValue)
|
||||||
{
|
{
|
||||||
type = CheckType(statement.ExplicitType.Value);
|
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)
|
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));
|
Scope.Declare(new Variable(statement.Name, type));
|
||||||
@@ -234,7 +248,7 @@ public sealed class TypeChecker
|
|||||||
|
|
||||||
private ExpressionNode CheckExpression(ExpressionSyntax node, TypeNode? expectedType = null)
|
private ExpressionNode CheckExpression(ExpressionSyntax node, TypeNode? expectedType = null)
|
||||||
{
|
{
|
||||||
return node switch
|
var result = node switch
|
||||||
{
|
{
|
||||||
AddressOfSyntax expression => CheckAddressOf(expression),
|
AddressOfSyntax expression => CheckAddressOf(expression),
|
||||||
ArrowFuncSyntax expression => CheckArrowFunc(expression, expectedType),
|
ArrowFuncSyntax expression => CheckArrowFunc(expression, expectedType),
|
||||||
@@ -250,6 +264,27 @@ public sealed class TypeChecker
|
|||||||
UnaryExpressionSyntax expression => CheckUnaryExpression(expression),
|
UnaryExpressionSyntax expression => CheckUnaryExpression(expression),
|
||||||
_ => throw new ArgumentOutOfRangeException(nameof(node))
|
_ => 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)
|
private AddressOfNode CheckAddressOf(AddressOfSyntax expression)
|
||||||
@@ -401,14 +436,14 @@ public sealed class TypeChecker
|
|||||||
{
|
{
|
||||||
var boundExpression = CheckExpression(expression.Target);
|
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 > 0)
|
||||||
{
|
{
|
||||||
if (interfaces.Length > 1)
|
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];
|
var @interface = interfaces[0];
|
||||||
@@ -418,7 +453,7 @@ public sealed class TypeChecker
|
|||||||
{
|
{
|
||||||
if (interfaceFuncs.Length > 1)
|
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];
|
var interfaceFunc = interfaceFuncs[0];
|
||||||
@@ -426,7 +461,7 @@ public sealed class TypeChecker
|
|||||||
var returnType = CheckType(interfaceFunc.Signature.ReturnType);
|
var returnType = CheckType(interfaceFunc.Signature.ReturnType);
|
||||||
var parameterTypes = interfaceFunc.Signature.Parameters.Select(p => CheckType(p.Type)).ToList();
|
var parameterTypes = interfaceFunc.Signature.Parameters.Select(p => CheckType(p.Type)).ToList();
|
||||||
var type = new FuncTypeNode(parameterTypes, returnType);
|
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