From 73baf3d73ba825627dfcde515e0a936104112ee7 Mon Sep 17 00:00:00 2001 From: nub31 Date: Wed, 10 Sep 2025 23:12:17 +0200 Subject: [PATCH] ... --- example/makefile | 4 +- src/compiler/NubLang.CLI/NubLang.CLI.csproj | 7 + src/compiler/NubLang.CLI/Program.cs | 36 +++- src/compiler/NubLang.CLI/assets/runtime.o | Bin 0 -> 4928 bytes src/compiler/NubLang.CLI/assets/x64.o | Bin 0 -> 2352 bytes .../NubLang/Generation/QBE/QBEGenerator.cs | 161 +++++++++--------- src/compiler/NubLang/TypeChecking/Module.cs | 17 +- .../NubLang/TypeChecking/Node/TypeNode.cs | 24 ++- src/compiler/NubLang/TypeResolver.cs | 34 +++- 9 files changed, 192 insertions(+), 91 deletions(-) create mode 100644 src/compiler/NubLang.CLI/assets/runtime.o create mode 100644 src/compiler/NubLang.CLI/assets/x64.o diff --git a/example/makefile b/example/makefile index 9fc5f56..4932cb8 100644 --- a/example/makefile +++ b/example/makefile @@ -1,8 +1,8 @@ -CC = clang +CC = gcc NUBC = ../src/compiler/NubLang.CLI/bin/Debug/net9.0/nubc .build/out: .build/out.a - $(CC) -g -o .build/out .build/out.a + $(CC) -ffreestanding -g -o .build/out .build/out.a .build/out.a: $(NUBC) src/main.nub $(NUBC) src/main.nub diff --git a/src/compiler/NubLang.CLI/NubLang.CLI.csproj b/src/compiler/NubLang.CLI/NubLang.CLI.csproj index 0550d0f..2f25112 100644 --- a/src/compiler/NubLang.CLI/NubLang.CLI.csproj +++ b/src/compiler/NubLang.CLI/NubLang.CLI.csproj @@ -13,4 +13,11 @@ + + + + + + + diff --git a/src/compiler/NubLang.CLI/Program.cs b/src/compiler/NubLang.CLI/Program.cs index 98406b2..55dc9d0 100644 --- a/src/compiler/NubLang.CLI/Program.cs +++ b/src/compiler/NubLang.CLI/Program.cs @@ -1,4 +1,5 @@ -using NubLang.CLI; +using System.Reflection; +using NubLang.CLI; using NubLang.Code; using NubLang.Diagnostics; using NubLang.Generation.QBE; @@ -6,6 +7,7 @@ using NubLang.Parsing; using NubLang.Parsing.Syntax; using NubLang.Tokenization; using NubLang.TypeChecking; +using Module = NubLang.TypeChecking.Module; var options = new Options(); @@ -120,6 +122,38 @@ for (var i = 0; i < typedModules.Count; i++) objectFiles.Add(objFilePath); } +var resources = Assembly.GetExecutingAssembly().GetManifestResourceNames(); + +string[] runtimeObjects = ["runtime.o", "x64.o"]; + +foreach (var runtimeObject in runtimeObjects) +{ + var runtime = resources.First(r => r.EndsWith(runtimeObject)); + + await using var reader = Assembly + .GetExecutingAssembly() + .GetManifestResourceStream(runtime); + + if (reader == null) + { + Console.Error.WriteLine($"Cannot open read stream to '{runtimeObject}'"); + return 1; + } + + var runtimePath = Path.Combine(".build", "runtime", runtimeObject); + var runtimeDir = Path.GetDirectoryName(runtimePath); + if (!string.IsNullOrEmpty(runtimeDir)) + { + Directory.CreateDirectory(runtimeDir); + } + + await using var writer = new FileStream(runtimePath, FileMode.Create); + + reader.CopyTo(writer); + + objectFiles.Add(runtimePath); +} + var outPath = options.OutputPath ?? Path.Combine(".build", "out.a"); var outDir = Path.GetDirectoryName(outPath); if (!string.IsNullOrEmpty(outDir)) diff --git a/src/compiler/NubLang.CLI/assets/runtime.o b/src/compiler/NubLang.CLI/assets/runtime.o new file mode 100644 index 0000000000000000000000000000000000000000..3024a903038d0a6bd92772b6f45c7fc2e1f26672 GIT binary patch literal 4928 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 Ogoc9hHc{zr#{U8^(4c|< literal 0 HcmV?d00001 diff --git a/src/compiler/NubLang/Generation/QBE/QBEGenerator.cs b/src/compiler/NubLang/Generation/QBE/QBEGenerator.cs index a93754d..4f956e2 100644 --- a/src/compiler/NubLang/Generation/QBE/QBEGenerator.cs +++ b/src/compiler/NubLang/Generation/QBE/QBEGenerator.cs @@ -11,7 +11,7 @@ public class QBEGenerator { private readonly QBEWriter _writer; private readonly TypedModule _module; - private readonly IReadOnlyList _moduleSignatures; + private readonly IReadOnlyDictionary _moduleSignatures; private readonly List _cStringLiterals = []; private readonly List _stringLiterals = []; @@ -23,7 +23,7 @@ public class QBEGenerator private int _stringLiteralIndex; private bool _codeIsReachable = true; - public QBEGenerator(TypedModule module, IReadOnlyList moduleSignatures) + public QBEGenerator(TypedModule module, IReadOnlyDictionary moduleSignatures) { _module = module; _moduleSignatures = moduleSignatures; @@ -42,11 +42,11 @@ public class QBEGenerator _stringLiteralIndex = 0; _codeIsReachable = true; - foreach (var moduleSignature in _moduleSignatures) + foreach (var (module, signature) in _moduleSignatures) { - foreach (var structType in moduleSignature.Symbols.Values.OfType()) + foreach (var structType in signature.StructTypes) { - EmitStructType(moduleSignature.Name, structType); + EmitStructType(module, structType); _writer.NewLine(); } } @@ -384,7 +384,7 @@ public class QBEGenerator _writer.Write(FuncQBETypeName(funcDef.Signature.ReturnType) + ' '); } - _writer.Write(LocalFuncName(_module.Name, funcDef)); + _writer.Write(LocalFuncName(_module.Name, funcDef.Name)); _writer.Write("("); foreach (var parameter in funcDef.Signature.Parameters) @@ -408,15 +408,17 @@ public class QBEGenerator private void EmitStructDefinition(StructNode structDef) { - _writer.WriteLine($"export function {StructCtorName(_module.Name, structDef.Name)}() {{"); - _writer.WriteLine("@start"); - _writer.Indented($"%struct =l alloc8 {SizeOf(structDef.)}"); - _writer.Indented("ret %struct"); - _writer.WriteLine("}"); + var type = TypeResolver.ResolveStructType(_module.Name, structDef.Name, _moduleSignatures); - for (var i = 0; i < structDef.Functions.Count; i++) + // _writer.WriteLine($"export function {StructCtorName(_module.Name, structDef.Name)}() {{"); + // _writer.WriteLine("@start"); + // _writer.Indented($"%struct =l alloc8 {SizeOf(type)}"); + // // todo(nub31): Finish constructor + // _writer.Indented("ret %struct"); + // _writer.WriteLine("}"); + + foreach (var function in structDef.Functions) { - var function = structDef.Functions[i]; _labelIndex = 0; _tmpIndex = 0; @@ -457,7 +459,7 @@ public class QBEGenerator foreach (var field in structType.Fields) { - _writer.Indented($"{StructDefQBEType(field)},"); + _writer.Indented($"{StructDefQBEType(field.Type)},"); } _writer.WriteLine("}"); @@ -479,9 +481,9 @@ public class QBEGenerator }; } - if (complexType is StructTypeNode structType) + if (complexType is StructTypeNode childStructType) { - return StructTypeName(structType.Module, structType.Name); + return StructTypeName(childStructType.Module, childStructType.Name); } return "l"; @@ -642,7 +644,9 @@ public class QBEGenerator ConvertToInterfaceNode convertToInterface => EmitConvertToInterface(convertToInterface), ConvertIntNode convertInt => EmitConvertInt(convertInt), ConvertFloatNode convertFloat => EmitConvertFloat(convertFloat), - VariableIdentifierNode identifier => EmitIdentifier(identifier), + VariableIdentifierNode identifier => EmitVariableIdentifier(identifier), + FuncIdentifierNode funcIdentifier => EmitFuncIdentifier(funcIdentifier), + FuncParameterIdentifierNode funcParameterIdentifier => EmitParameterFuncIdentifier(funcParameterIdentifier), LiteralNode literal => EmitLiteral(literal), UnaryExpressionNode unaryExpression => EmitUnaryExpression(unaryExpression), StructFieldAccessNode structFieldAccess => EmitStructFieldAccess(structFieldAccess), @@ -652,9 +656,24 @@ public class QBEGenerator }; } - private string EmitIdentifier(VariableIdentifierNode variableIdentifier) + private string EmitFuncIdentifier(FuncIdentifierNode localFuncIdent) { - throw new NotImplementedException(); + // todo(nub31): Support for extern funcs + return LocalFuncName(localFuncIdent.Module, localFuncIdent.Name); + } + + private string EmitVariableIdentifier(VariableIdentifierNode variableIdent) + { + var address = EmitAddressOfVariableIdent(variableIdent); + + return variableIdent.Type.IsSimpleType(out _, out _) + ? EmitLoad(variableIdent.Type, address) + : address; + } + + private string EmitParameterFuncIdentifier(FuncParameterIdentifierNode funcParameterIdent) + { + return "%" + funcParameterIdent.Name; } private string EmitArrayIndexAccess(ArrayIndexAccessNode arrayIndexAccess) @@ -710,43 +729,43 @@ public class QBEGenerator { return addressOf switch { - // ArrayIndexAccessNode arrayIndexAccess => EmitAddressOfArrayIndexAccess(arrayIndexAccess), - // StructFieldAccessNode structFieldAccess => EmitAddressOfStructFieldAccess(structFieldAccess), - // VariableIdentNode variableIdent => EmitAddressOfVariableIdent(variableIdent), + ArrayIndexAccessNode arrayIndexAccess => EmitAddressOfArrayIndexAccess(arrayIndexAccess), + StructFieldAccessNode structFieldAccess => EmitAddressOfStructFieldAccess(structFieldAccess), + VariableIdentifierNode variableIdent => EmitAddressOfVariableIdent(variableIdent), _ => throw new ArgumentOutOfRangeException(nameof(addressOf)) }; } - // private string EmitAddressOfArrayIndexAccess(ArrayIndexAccessNode arrayIndexAccess) - // { - // var array = EmitExpression(arrayIndexAccess.Target); - // var index = EmitExpression(arrayIndexAccess.Index); - // - // var elementType = ((ArrayTypeNode)arrayIndexAccess.Target.Type).ElementType; - // - // var offset = TmpName(); - // _writer.Indented($"{offset} =l mul {index}, {SizeOf(elementType)}"); - // _writer.Indented($"{offset} =l add {offset}, 8"); - // _writer.Indented($"{offset} =l add {array}, {offset}"); - // return offset; - // } - // - // private string EmitAddressOfStructFieldAccess(StructFieldAccessNode structFieldAccess) - // { - // var target = EmitExpression(structFieldAccess.Target); - // - // var structDef = _definitionTable.LookupStruct(structFieldAccess.StructType.Name); - // var offset = OffsetOf(structDef, structFieldAccess.Field); - // - // var address = TmpName(); - // _writer.Indented($"{address} =l add {target}, {offset}"); - // return address; - // } - // - // private string EmitAddressOfVariableIdent(VariableIdentNode variableIdent) - // { - // return "%" + variableIdent.Name; - // } + private string EmitAddressOfArrayIndexAccess(ArrayIndexAccessNode arrayIndexAccess) + { + var array = EmitExpression(arrayIndexAccess.Target); + var index = EmitExpression(arrayIndexAccess.Index); + + var elementType = ((ArrayTypeNode)arrayIndexAccess.Target.Type).ElementType; + + var offset = TmpName(); + _writer.Indented($"{offset} =l mul {index}, {SizeOf(elementType)}"); + _writer.Indented($"{offset} =l add {offset}, 8"); + _writer.Indented($"{offset} =l add {array}, {offset}"); + return offset; + } + + private string EmitAddressOfStructFieldAccess(StructFieldAccessNode structFieldAccess) + { + var target = EmitExpression(structFieldAccess.Target); + + var structType = TypeResolver.ResolveStructType(structFieldAccess.StructType.Module, structFieldAccess.StructType.Name, _moduleSignatures); + var offset = OffsetOf(structType, structFieldAccess.Field); + + var address = TmpName(); + _writer.Indented($"{address} =l add {target}, {offset}"); + return address; + } + + private string EmitAddressOfVariableIdent(VariableIdentifierNode variableIdent) + { + return "%" + variableIdent.Name; + } private string EmitBinaryExpression(BinaryExpressionNode binaryExpression) { @@ -1006,21 +1025,11 @@ public class QBEGenerator var size = SizeOf(structInitializer.StructType); _writer.Indented($"{destination} =l alloc8 {size}"); - foreach (var field in structInitializer.StructType.Fields) + foreach (var (field, value) in structInitializer.Initializers) { - if (!structInitializer.Initializers.TryGetValue(field.Name, out var valueExpression)) - { - valueExpression = field.Value.Value; - } - - 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)}"); - EmitCopyInto(valueExpression, offset); + _writer.Indented($"{offset} =l add {destination}, {OffsetOf(structInitializer.StructType, field)}"); + EmitCopyInto(value, offset); } return destination; @@ -1086,8 +1095,7 @@ public class QBEGenerator private string EmitStructFuncCall(StructFuncCallNode structFuncCall) { - var structDef = _definitionTable.LookupStruct(structFuncCall.StructType.Name); - var func = StructFuncName(structDef.Name, structFuncCall.Name); + var func = StructFuncName(structFuncCall.StructType.Module, structFuncCall.StructType.Name, structFuncCall.Name); var thisParameter = EmitExpression(structFuncCall.StructExpression); @@ -1116,8 +1124,7 @@ public class QBEGenerator { var target = EmitExpression(interfaceFuncCall.InterfaceExpression); - var interfaceDef = _definitionTable.LookupInterface(interfaceFuncCall.InterfaceType.Name); - var functionIndex = interfaceDef.Functions.ToList().FindIndex(x => x.Name == interfaceFuncCall.Name); + var functionIndex = interfaceFuncCall.InterfaceType.Functions.ToList().FindIndex(x => x.Name == interfaceFuncCall.Name); var offset = functionIndex * 8; var vtable = TmpName(); @@ -1173,7 +1180,7 @@ public class QBEGenerator _writer.Indented($"{destination} =l alloc8 {SizeOf(convertToInterface.InterfaceType)}"); var interfaceVtablePointer = TmpName(); - _writer.Indented($"{interfaceVtablePointer} =l add {StructVtableName(convertToInterface.StructType.Name)}, {vtableOffset}"); + _writer.Indented($"{interfaceVtablePointer} =l add {StructVtableName(convertToInterface.StructType.Module, convertToInterface.StructType.Name)}, {vtableOffset}"); _writer.Indented($"storel {interfaceVtablePointer}, {destination}"); var objectPointer = TmpName(); @@ -1287,11 +1294,13 @@ public class QBEGenerator { var offset = 0; + var fields = new List(structType.Fields.Count); + foreach (var field in structType.Fields) { - var fieldAlignment = AlignmentOf(field); + var fieldAlignment = AlignmentOf(field.Type); offset = AlignTo(offset, fieldAlignment); - offset += SizeOf(field); + offset += SizeOf(field.Type); } var structAlignment = CalculateStructAlignment(structType); @@ -1331,7 +1340,7 @@ public class QBEGenerator foreach (var field in structType.Fields) { - var fieldAlignment = AlignmentOf(field); + var fieldAlignment = AlignmentOf(field.Type); maxAlignment = Math.Max(maxAlignment, fieldAlignment); } @@ -1343,7 +1352,7 @@ public class QBEGenerator return (offset + alignment - 1) & ~(alignment - 1); } - private static int OffsetOf(StructNode structDef, string member) + private static int OffsetOf(StructTypeNode structDef, string member) { var offset = 0; @@ -1385,9 +1394,9 @@ public class QBEGenerator return $"$string{++_stringLiteralIndex}"; } - private string LocalFuncName(string module, LocalFuncNode funcDef) + private string LocalFuncName(string module, string name) { - return $"${module}.{funcDef.Name}"; + return $"${module}.{name}"; } private string ExternFuncName(ExternFuncNode funcDef) diff --git a/src/compiler/NubLang/TypeChecking/Module.cs b/src/compiler/NubLang/TypeChecking/Module.cs index 598604e..e522ca7 100644 --- a/src/compiler/NubLang/TypeChecking/Module.cs +++ b/src/compiler/NubLang/TypeChecking/Module.cs @@ -107,12 +107,13 @@ public class ModuleSignature } case InterfaceSyntax interfaceDef: { - var functions = new Dictionary(); - foreach (var function in interfaceDef.Functions) + var functions = new List(); + for (var i = 0; i < interfaceDef.Functions.Count; i++) { + var function = interfaceDef.Functions[i]; var parameters = function.Signature.Parameters.Select(p => TypeResolver.ResolveType(p.Type, modules)).ToList(); var returnType = TypeResolver.ResolveType(function.Signature.ReturnType, modules); - functions.Add(function.Name, new FuncTypeNode(parameters, returnType)); + functions.Add(new InterfaceTypeFunc(function.Name, new FuncTypeNode(parameters, returnType), i)); } var type = new InterfaceTypeNode(moduleName, interfaceDef.Name, functions); @@ -121,14 +122,18 @@ public class ModuleSignature } case StructSyntax structDef: { - var fields = structDef.Fields.Select(x => new StructTypeField(x.Name, TypeResolver.ResolveType(x.Type, modules), x.Value.HasValue)).ToList(); + var fields = new List(); + foreach (var field in structDef.Fields) + { + fields.Add(new StructTypeField(field.Name, TypeResolver.ResolveType(field.Type, modules), field.Index, field.Value.HasValue)); + } - var functions = new Dictionary(); + var functions = new List(); foreach (var function in structDef.Functions) { var parameters = function.Signature.Parameters.Select(p => TypeResolver.ResolveType(p.Type, modules)).ToList(); var returnType = TypeResolver.ResolveType(function.Signature.ReturnType, modules); - functions.Add(function.Name, new FuncTypeNode(parameters, returnType)); + functions.Add(new StructTypeFunc(function.Name, new FuncTypeNode(parameters, returnType))); } var interfaceImplementations = new List(); diff --git a/src/compiler/NubLang/TypeChecking/Node/TypeNode.cs b/src/compiler/NubLang/TypeChecking/Node/TypeNode.cs index 2f5bbdd..55d29aa 100644 --- a/src/compiler/NubLang/TypeChecking/Node/TypeNode.cs +++ b/src/compiler/NubLang/TypeChecking/Node/TypeNode.cs @@ -174,19 +174,26 @@ public class StringTypeNode : ComplexTypeNode public override int GetHashCode() => HashCode.Combine(typeof(StringTypeNode)); } -public class StructTypeField(string name, TypeNode type, bool hasDefaultValue) +public class StructTypeField(string name, TypeNode type, int index, bool hasDefaultValue) { public string Name { get; } = name; public TypeNode Type { get; } = type; + public int Index { get; } = index; public bool HasDefaultValue { get; } = hasDefaultValue; } -public class StructTypeNode(string module, string name, IReadOnlyList fields, IReadOnlyDictionary functions, IReadOnlyList interfaceImplementations) : ComplexTypeNode +public class StructTypeFunc(string name, FuncTypeNode type) +{ + public string Name { get; } = name; + public FuncTypeNode Type { get; } = type; +} + +public class StructTypeNode(string module, string name, IReadOnlyList fields, IReadOnlyList functions, IReadOnlyList interfaceImplementations) : ComplexTypeNode { public string Module { get; } = module; public string Name { get; } = name; public IReadOnlyList Fields { get; set; } = fields; - public IReadOnlyDictionary Functions { get; set; } = functions; + public IReadOnlyList Functions { get; set; } = functions; public IReadOnlyList InterfaceImplementations { get; set; } = interfaceImplementations; public override string ToString() => Name; @@ -194,11 +201,18 @@ public class StructTypeNode(string module, string name, IReadOnlyList HashCode.Combine(typeof(StructTypeNode), Name); } -public class InterfaceTypeNode(string module, string name, IReadOnlyDictionary functions) : ComplexTypeNode +public class InterfaceTypeFunc(string name, FuncTypeNode type, int index) +{ + public string Name { get; } = name; + public FuncTypeNode Type { get; } = type; + public int Index { get; } = index; +} + +public class InterfaceTypeNode(string module, string name, IReadOnlyList functions) : ComplexTypeNode { public string Module { get; } = module; public string Name { get; } = name; - public IReadOnlyDictionary Functions { get; set; } = functions; + public IReadOnlyList Functions { get; set; } = functions; public override string ToString() => Name; public override bool Equals(TypeNode? other) => other is InterfaceTypeNode interfaceType && Name == interfaceType.Name && Module == interfaceType.Module; diff --git a/src/compiler/NubLang/TypeResolver.cs b/src/compiler/NubLang/TypeResolver.cs index 7e49649..972dec2 100644 --- a/src/compiler/NubLang/TypeResolver.cs +++ b/src/compiler/NubLang/TypeResolver.cs @@ -43,6 +43,38 @@ public static class TypeResolver return interfaceType; } - throw new Exception("Type not found: " + typeName); + throw new Exception($"Type {typeName} not found in module {moduleName}"); + } + + public static StructTypeNode ResolveStructType(string moduleName, string structName, IReadOnlyDictionary modules) + { + if (!modules.TryGetValue(moduleName, out var module)) + { + throw new Exception("Module not found: " + moduleName); + } + + var structType = module.StructTypes.FirstOrDefault(x => x.Name == structName); + if (structType != null) + { + return structType; + } + + throw new Exception($"Struct type {structName} not found in module {moduleName}"); + } + + public static InterfaceTypeNode ResolveInterfaceType(string moduleName, string structName, IReadOnlyDictionary modules) + { + if (!modules.TryGetValue(moduleName, out var module)) + { + throw new Exception("Module not found: " + moduleName); + } + + var structType = module.InterfaceTypes.FirstOrDefault(x => x.Name == structName); + if (structType != null) + { + return structType; + } + + throw new Exception($"Interface type {structName} not found in module {moduleName}"); } } \ No newline at end of file