diff --git a/example/src/main.nub b/example/src/main.nub index 1048304..af8ed2f 100644 --- a/example/src/main.nub +++ b/example/src/main.nub @@ -16,18 +16,18 @@ struct Human : Printable, Stringable func str(): cstring { - return this^.name + return this.name } func print() { - puts(this^.str()) + puts(this.str()) } } func main(args: []cstring): i64 { - let human: Stringable = alloc Human { + let human = alloc Human { name = "oliver" } diff --git a/src/compiler/NubLang.CLI/Program.cs b/src/compiler/NubLang.CLI/Program.cs index 7fc401b..69e9658 100644 --- a/src/compiler/NubLang.CLI/Program.cs +++ b/src/compiler/NubLang.CLI/Program.cs @@ -117,9 +117,10 @@ var typedDefinitionTable = new TypedDefinitionTable(typedSyntaxTrees); var objectFiles = new List(); -foreach (var syntaxTree in typedSyntaxTrees) +for (var i = 0; i < typedSyntaxTrees.Count; i++) { - var outFileName = HexString.CreateUnique(8); + var syntaxTree = typedSyntaxTrees[i]; + var outFileName = Path.GetFileNameWithoutExtension(options.Files[i].Path); var generator = new QBEGenerator(syntaxTree, typedDefinitionTable); var ssa = generator.Emit(); diff --git a/src/compiler/NubLang/Generation/QBE/QBEGenerator.Expression.cs b/src/compiler/NubLang/Generation/QBE/QBEGenerator.Expression.cs index ced489e..b2caa72 100644 --- a/src/compiler/NubLang/Generation/QBE/QBEGenerator.Expression.cs +++ b/src/compiler/NubLang/Generation/QBE/QBEGenerator.Expression.cs @@ -110,7 +110,7 @@ public partial class QBEGenerator var value = EmitExpression(addressOf.Expression); if (value.Kind != ValKind.Pointer) { - throw new UnreachableException("Tried to take address of non-pointer type. This should have been causht in the type checker"); + throw new UnreachableException("Tried to take address of non-pointer type. This should have been caught in the type checker"); } return new Val(value.Name, addressOf.Type, ValKind.Direct); @@ -333,11 +333,6 @@ public partial class QBEGenerator _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)) @@ -345,7 +340,10 @@ public partial class QBEGenerator valueExpression = field.Value.Value; } - Debug.Assert(valueExpression != null); + if (valueExpression == null) + { + throw new UnreachableException("Value of field in uninitialized. This should have been caught in the type checker"); + } var offset = TmpName(); _writer.Indented($"{offset} =l add {destination}, {OffsetOf(structDef, field.Name)}"); @@ -423,13 +421,12 @@ public partial class QBEGenerator private Val EmitStructFuncAccess(StructFuncAccessNode structFuncAccess) { - var target = EmitExpression(structFuncAccess.Target); - Debug.Assert(target.Kind == ValKind.Pointer); + var target = EmitUnwrap(EmitExpression(structFuncAccess.Target)); var structDef = _definitionTable.LookupStruct(structFuncAccess.StructType.Name); var func = StructFuncName(structDef.Name, structFuncAccess.Func); - return new Val(func, structFuncAccess.Type, ValKind.Direct, target.Name); + return new Val(func, structFuncAccess.Type, ValKind.Direct, target); } private Val EmitInterfaceFuncAccess(InterfaceFuncAccessNode interfaceFuncAccess) @@ -449,13 +446,16 @@ public partial class QBEGenerator var func = TmpName(); _writer.Indented($"{func} =l loadl {funcOffset}"); + var dataPointer = TmpName(); + _writer.Indented($"{dataPointer} =l add {target}, 8"); + var data = TmpName(); - _writer.Indented($"{data} =l add {target}, 8"); + _writer.Indented($"{data} =l loadl {dataPointer}"); return new Val(func, interfaceFuncAccess.Type, ValKind.Direct, data); } - private Val EmitInterfaceInitializer(InterfaceInitializerNode interfaceInitializer) + private Val EmitInterfaceInitializer(InterfaceInitializerNode interfaceInitializer, string? destination = null) { var implementation = EmitUnwrap(EmitExpression(interfaceInitializer.Implementation)); @@ -470,27 +470,28 @@ public partial class QBEGenerator vtableOffset += interfaceImplementation.Functions.Count * 8; } - var result = TmpName(); - _writer.Indented($"{result} =l alloc8 16"); + if (destination == null) + { + destination = TmpName(); + _writer.Indented($"{destination} =l alloc8 {SizeOf(interfaceInitializer.InterfaceType)}"); + } var interfaceVtablePointer = TmpName(); _writer.Indented($"{interfaceVtablePointer} =l add {StructVtableName(interfaceInitializer.StructType.Name)}, {vtableOffset}"); - _writer.Indented($"storel {interfaceVtablePointer}, {result}"); + _writer.Indented($"storel {interfaceVtablePointer}, {destination}"); var objectPointer = TmpName(); - _writer.Indented($"{objectPointer} =l add {result}, 8"); + _writer.Indented($"{objectPointer} =l add {destination}, 8"); _writer.Indented($"storel {implementation}, {objectPointer}"); - return new Val(result, interfaceInitializer.InterfaceType, ValKind.Direct); + return new Val(destination, interfaceInitializer.InterfaceType, ValKind.Direct); } private Val EmitFuncCall(FuncCallNode funcCall) { var expression = EmitExpression(funcCall.Expression); - var funcPointer = EmitUnwrap(expression); var parameterStrings = new List(); - if (expression.ThisArg != null) { parameterStrings.Add($"l {expression.ThisArg}"); @@ -502,6 +503,7 @@ public partial class QBEGenerator parameterStrings.Add($"{FuncQBETypeName(parameter.Type)} {copy}"); } + var funcPointer = EmitUnwrap(expression); if (funcCall.Type is VoidTypeNode) { _writer.Indented($"call {funcPointer}({string.Join(", ", parameterStrings)})"); diff --git a/src/compiler/NubLang/Generation/QBE/QBEGenerator.Statement.cs b/src/compiler/NubLang/Generation/QBE/QBEGenerator.Statement.cs index 7121b58..0871558 100644 --- a/src/compiler/NubLang/Generation/QBE/QBEGenerator.Statement.cs +++ b/src/compiler/NubLang/Generation/QBE/QBEGenerator.Statement.cs @@ -41,7 +41,11 @@ public partial class QBEGenerator private void EmitAssignment(AssignmentNode assignment) { var destination = EmitExpression(assignment.Target); - Debug.Assert(destination.Kind == ValKind.Pointer); + if (destination.Kind != ValKind.Pointer) + { + throw new UnreachableException("Destination of assignment must be a pointer. This should be caught in the type checker"); + } + EmitCopyIntoOrInitialize(assignment.Value, destination.Name); } diff --git a/src/compiler/NubLang/Generation/QBE/QBEGenerator.cs b/src/compiler/NubLang/Generation/QBE/QBEGenerator.cs index 718f449..7486345 100644 --- a/src/compiler/NubLang/Generation/QBE/QBEGenerator.cs +++ b/src/compiler/NubLang/Generation/QBE/QBEGenerator.cs @@ -224,6 +224,11 @@ public partial class QBEGenerator EmitStructInitializer(structInitializer, destinationPointer); return true; } + case InterfaceInitializerNode interfaceInitializer: + { + EmitInterfaceInitializer(interfaceInitializer, destinationPointer); + return true; + } case LiteralNode { Kind: LiteralKind.String } literal: { EmitStore(source.Type, EmitUnwrap(EmitLiteral(literal)), destinationPointer); @@ -250,9 +255,9 @@ public partial class QBEGenerator } else { - if (complexType is StructTypeNode structType) + if (complexType is StructTypeNode or InterfaceTypeNode) { - EmitMemcpy(value, destinationPointer, SizeOf(structType).ToString()); + EmitMemcpy(value, destinationPointer, SizeOf(complexType).ToString()); } else { @@ -261,7 +266,6 @@ public partial class QBEGenerator ArrayTypeNode arrayType => EmitArraySizeInBytes(arrayType, value), CStringTypeNode => EmitCStringSizeInBytes(value), StringTypeNode => EmitStringSizeInBytes(value), - InterfaceTypeNode => 16.ToString(), _ => throw new ArgumentOutOfRangeException(nameof(source.Type)) }; @@ -311,7 +315,7 @@ public partial class QBEGenerator ArrayTypeNode arrayType => EmitArraySizeInBytes(arrayType, value), CStringTypeNode => EmitCStringSizeInBytes(value), StringTypeNode => EmitStringSizeInBytes(value), - InterfaceTypeNode => 16.ToString(), + InterfaceTypeNode interfaceType => SizeOf(interfaceType).ToString(), StructTypeNode structType => SizeOf(structType).ToString(), _ => throw new ArgumentOutOfRangeException(nameof(source.Type)) }; @@ -486,11 +490,6 @@ public partial class QBEGenerator { var offset = 0; - // if (structType.InterfaceImplementations.Any()) - // { - // offset = 8; - // } - foreach (var field in structType.Fields) { var fieldAlignment = AlignmentOf(field); diff --git a/src/compiler/NubLang/Parsing/Parser.cs b/src/compiler/NubLang/Parsing/Parser.cs index 2719afc..2372792 100644 --- a/src/compiler/NubLang/Parsing/Parser.cs +++ b/src/compiler/NubLang/Parsing/Parser.cs @@ -73,7 +73,7 @@ public sealed class Parser if (thisArg != null) { - parameters.Add(new FuncParameterSyntax([], "this", new PointerTypeSyntax([], thisArg))); + parameters.Add(new FuncParameterSyntax([], "this", thisArg)); } ExpectSymbol(Symbol.OpenParen);