diff --git a/compiler/NubLang.CLI/Program.cs b/compiler/NubLang.CLI/Program.cs index 314327a..0482737 100644 --- a/compiler/NubLang.CLI/Program.cs +++ b/compiler/NubLang.CLI/Program.cs @@ -48,39 +48,13 @@ Directory.CreateDirectory(".build"); var typedModules = modules.Select(x => (x.Key, TypedModule.FromModule(x.Key, x.Value, modules))).ToDictionary(); -var moduleHeaders = new List(); - -var commonHeaderOut = Path.Combine(".build", "runtime.h"); - -File.WriteAllText(commonHeaderOut, """ - #include - - void *rc_alloc(size_t size, void (*destructor)(void *self)); - void rc_retain(void *obj); - void rc_release(void *obj); - - typedef struct - { - unsigned long long length; - char *data; - } nub_string; - - typedef struct - { - unsigned long long length; - void *data; - } nub_slice; - """); - -moduleHeaders.Add(commonHeaderOut); +Directory.CreateDirectory(Path.Combine(".build", "modules")); foreach (var typedModule in typedModules) { var header = HeaderGenerator.Generate(typedModule.Key, typedModule.Value); - var headerOut = Path.Combine(".build", "modules", typedModule.Key + ".h"); - Directory.CreateDirectory(Path.Combine(".build", "modules")); + var headerOut = Path.Combine(Path.Combine(".build", "modules"), typedModule.Key + ".h"); File.WriteAllText(headerOut, header); - moduleHeaders.Add(headerOut); } for (var i = 0; i < args.Length; i++) @@ -106,7 +80,7 @@ foreach (var cPath in cPaths) { var objectPath = Path.ChangeExtension(cPath, "o"); using var compileProcess = Process.Start("clang", [ - ..moduleHeaders.SelectMany(x => new[] { "-include", x }), + "-I.build", "-ffreestanding", "-std=c23", "-g", "-c", "-o", objectPath, diff --git a/compiler/NubLang/Generation/CType.cs b/compiler/NubLang/Generation/CType.cs index daad988..0ccc702 100644 --- a/compiler/NubLang/Generation/CType.cs +++ b/compiler/NubLang/Generation/CType.cs @@ -19,7 +19,8 @@ public static class CType NubConstArrayType a => CreateConstArrayType(a, variableName, constArraysAsPointers), NubArrayType a => CreateArrayType(a, variableName), NubFuncType f => CreateFuncType(f, variableName), - NubStructType s => $"{s.Module}_{s.Name}_{NameMangler.Mangle(s)}" + (variableName != null ? $" {variableName}" : ""), + // NubStructType s => $"{s.Module}_{s.Name}_{NameMangler.Mangle(s)}" + (variableName != null ? $" {variableName}" : ""), + NubStructType s => $"{s.Module}_{s.Name}" + (variableName != null ? $" {variableName}" : ""), _ => throw new NotSupportedException($"C type generation not supported for: {type}") }; } @@ -60,12 +61,12 @@ public static class CType return baseType + "*" + (varName != null ? $" {varName}" : ""); } - private static string CreateConstArrayType(NubConstArrayType arr, string? varName, bool inStructDef) + private static string CreateConstArrayType(NubConstArrayType arr, string? varName, bool constArraysAsPointers) { var elementType = Create(arr.ElementType); // Treat const arrays as pointers unless in a struct definition - if (!inStructDef) + if (constArraysAsPointers) { return elementType + "*" + (varName != null ? $" {varName}" : ""); } diff --git a/compiler/NubLang/Generation/Generator.cs b/compiler/NubLang/Generation/Generator.cs index acc3f45..0620dd4 100644 --- a/compiler/NubLang/Generation/Generator.cs +++ b/compiler/NubLang/Generation/Generator.cs @@ -38,6 +38,34 @@ public class Generator public string Emit() { + foreach (var importNode in _compilationUnit.OfType()) + { + _writer.WriteLine($"#include "); + } + + _writer.WriteLine($"#include "); + + _writer.WriteLine(""" + #include + + void *rc_alloc(size_t size, void (*destructor)(void *self)); + void rc_retain(void *obj); + void rc_release(void *obj); + + typedef struct + { + unsigned long long length; + char *data; + } nub_string; + + typedef struct + { + unsigned long long length; + void *data; + } nub_slice; + + """); + foreach (var structType in _compilationUnit.OfType()) { _writer.WriteLine($"void {CType.Create(structType.StructType)}_create({CType.Create(structType.StructType)} *self)"); @@ -50,6 +78,7 @@ public class Generator { var value = EmitExpression(field.Value); _writer.WriteLine($"self->{field.NameToken.Value} = {value}"); + EmitConstructor($"self->{field.NameToken.Value}", field.Type); } } } @@ -65,7 +94,18 @@ public class Generator { if (field.Type is NubRefType) { - _writer.WriteLine($"rc_release(self->{field.NameToken.Value});"); + _writer.WriteLine($"if (self->{field.NameToken.Value})"); + _writer.WriteLine("{"); + using (_writer.Indent()) + { + EmitDestructor($"self->{field.NameToken.Value}", field.Type); + } + + _writer.WriteLine("}"); + } + else + { + EmitDestructor($"self->{field.NameToken.Value}", field.Type); } } } @@ -113,6 +153,7 @@ public class Generator private void EmitStatement(StatementNode statementNode) { EmitLine(statementNode.Tokens.FirstOrDefault()); + switch (statementNode) { case AssignmentNode assignmentNode: @@ -167,10 +208,10 @@ public class Generator private void EmitLine(Token? token) { - if (token == null) return; - var file = token.Span.FilePath; - var line = token.Span.Start.Line; - _writer.WriteLine($"#line {line} \"{file}\""); + // if (token == null) return; + // var file = token.Span.FilePath; + // var line = token.Span.Start.Line; + // _writer.WriteLine($"#line {line} \"{file}\""); } private void EmitAssignment(AssignmentNode assignmentNode) @@ -181,7 +222,6 @@ public class Generator if (assignmentNode.Target.Type is NubRefType) { _writer.WriteLine($"rc_retain({value});"); - Scope.Defer(() => _writer.WriteLine($"rc_release({value});")); _writer.WriteLine($"rc_release({target});"); } @@ -304,17 +344,18 @@ public class Generator private void EmitVariableDeclaration(VariableDeclarationNode variableDeclarationNode) { + Scope.AddVariable(variableDeclarationNode.NameToken.Value, variableDeclarationNode.Type); + if (variableDeclarationNode.Assignment != null) { var value = EmitExpression(variableDeclarationNode.Assignment); + _writer.WriteLine($"{CType.Create(variableDeclarationNode.Type, variableDeclarationNode.NameToken.Value)} = {value};"); + if (variableDeclarationNode.Type is NubRefType) { - _writer.WriteLine($"rc_retain({value});"); - Scope.Defer(() => _writer.WriteLine($"rc_release({value});")); + _writer.WriteLine($"rc_retain({variableDeclarationNode.NameToken.Value});"); } - - _writer.WriteLine($"{CType.Create(variableDeclarationNode.Type, variableDeclarationNode.NameToken.Value)} = {value};"); } else { @@ -444,14 +485,18 @@ public class Generator private string EmitConstArrayInitializer(ConstArrayInitializerNode arrayInitializerNode) { - var values = new List(); - foreach (var value in arrayInitializerNode.Values) + var arrayType = (NubConstArrayType)arrayInitializerNode.Type; + + var tmp = NewTmp(); + _writer.WriteLine($"{CType.Create(arrayType.ElementType)} {tmp}[{arrayType.Size}] = {{0}};"); + + for (var i = 0; i < arrayInitializerNode.Values.Count; i++) { - values.Add(EmitExpression(value)); + var valueName = EmitExpression(arrayInitializerNode.Values[i]); + _writer.WriteLine($"{tmp}[{i}] = {valueName};"); } - var arrayType = (NubConstArrayType)arrayInitializerNode.Type; - return $"({CType.Create(arrayType.ElementType)}[{arrayType.Size}]){{{string.Join(", ", values)}}}"; + return tmp; } private string EmitDereference(DereferenceNode dereferenceNode) @@ -543,13 +588,16 @@ public class Generator _writer.WriteLine($"{CType.Create(type)} {tmp} = ({CType.Create(type)})rc_alloc(sizeof({CType.Create(structType)}), (void (*)(void *)){CType.Create(structType)}_destroy);"); Scope.Defer(() => _writer.WriteLine($"rc_release({tmp});")); - _writer.WriteLine($"*{tmp} = ({CType.Create(structType)}){{{0}}};"); - _writer.WriteLine($"{CType.Create(structType)}_create({tmp});"); + EmitConstructor(tmp, structType); foreach (var initializer in refStructInitializerNode.Initializers) { var value = EmitExpression(initializer.Value); _writer.WriteLine($"{tmp}->{initializer.Key} = {value};"); + if (initializer.Value.Type is NubRefType) + { + _writer.WriteLine($"rc_retain({tmp}->{initializer.Key});"); + } } return tmp; @@ -582,7 +630,7 @@ public class Generator var tmp = NewTmp(); _writer.WriteLine($"{CType.Create(structType)} {tmp} = ({CType.Create(structType)}){{0}};"); - _writer.WriteLine($"{CType.Create(structType)}_create(&{tmp});"); + EmitConstructor($"&{tmp}", structType); foreach (var initializer in structInitializerNode.Initializers) { @@ -650,16 +698,82 @@ public class Generator foreach (var statementNode in blockNode.Statements) { EmitStatement(statementNode); + + if (statementNode != blockNode.Statements.Last()) + { + _writer.WriteLine(); + } } } private void EmitScopeCleanup() { + if (Scope.IsTerminated()) + { + return; + } + + Scope.Terminate(); + + var deferredStack = Scope.GetDeferred(); while (deferredStack.TryPop(out var deferred)) { deferred.Invoke(); } + + var variables = Scope.GetVariables(); + while (variables.TryPop(out var variable)) + { + EmitDestructor(variable.Ident, variable.Type); + } + } + + private void EmitConstructor(string target, NubType type) + { + switch (type) + { + case NubStructType structType: + { + _writer.WriteLine($"{CType.Create(structType)}_create({target});"); + break; + } + case NubRefType: + { + _writer.WriteLine($"rc_retain({target});"); + break; + } + } + } + + private void EmitDestructor(string target, NubType type) + { + switch (type) + { + case NubStructType structType: + { + _writer.WriteLine($"{CType.Create(structType)}_destroy({target});"); + break; + } + case NubConstArrayType constArrayType: + { + var index = NewTmp(); + _writer.WriteLine($"for (unsigned long long {index} = 0; {index} < {constArrayType.Size}; ++{index})"); + _writer.WriteLine("{"); + using (_writer.Indent()) + { + EmitDestructor($"&({target}[{index}])", constArrayType.ElementType); + } + + _writer.WriteLine("}"); + break; + } + case NubRefType: + { + _writer.WriteLine($"rc_release({target});"); + break; + } + } } private ScopeDisposer BeginScope() @@ -678,9 +792,24 @@ public class Generator } } +public class Variable(string ident, NubType type) +{ + public string Ident { get; } = ident; + public NubType Type { get; } = type; +} + public class Scope { + private bool _hasTerminated = false; private readonly List _deferred = []; + private readonly List _variables = []; + + public void Terminate() + { + _hasTerminated = true; + } + + public bool IsTerminated() => _hasTerminated; public void Defer(Action action) { @@ -688,4 +817,11 @@ public class Scope } public Stack GetDeferred() => new(_deferred); + + public void AddVariable(string ident, NubType type) + { + _variables.Add(new Variable(ident, type)); + } + + public Stack GetVariables() => new(_variables); } \ No newline at end of file diff --git a/compiler/NubLang/Generation/HeaderGenerator.cs b/compiler/NubLang/Generation/HeaderGenerator.cs index 059cb22..173d600 100644 --- a/compiler/NubLang/Generation/HeaderGenerator.cs +++ b/compiler/NubLang/Generation/HeaderGenerator.cs @@ -1,4 +1,3 @@ -using NubLang.Ast; using NubLang.Syntax; namespace NubLang.Generation; @@ -14,6 +13,11 @@ public static class HeaderGenerator { var writer = new IndentedTextWriter(); + foreach (var import in module.Imports) + { + writer.WriteLine($"#include \"{import}.h\""); + } + writer.WriteLine(); foreach (var structType in module.StructTypes) diff --git a/compiler/NubLang/Syntax/Module.cs b/compiler/NubLang/Syntax/Module.cs index 7765177..c635fb9 100644 --- a/compiler/NubLang/Syntax/Module.cs +++ b/compiler/NubLang/Syntax/Module.cs @@ -48,4 +48,13 @@ public sealed class Module .Where(x => x.Exported || includePrivate) .ToList(); } + + public List Imports() + { + return _definitions + .OfType() + .Select(x => x.NameToken.Value) + .Distinct() + .ToList(); + } } \ No newline at end of file diff --git a/compiler/NubLang/Syntax/TypedModule.cs b/compiler/NubLang/Syntax/TypedModule.cs index ba336e0..01b4b30 100644 --- a/compiler/NubLang/Syntax/TypedModule.cs +++ b/compiler/NubLang/Syntax/TypedModule.cs @@ -36,15 +36,17 @@ public sealed class TypedModule structTypes.Add(new NubStructType(name, structSyntax.NameToken.Value, fields)); } - return new TypedModule(functionPrototypes, structTypes); + return new TypedModule(functionPrototypes, structTypes, module.Imports()); } - public TypedModule(List functionPrototypes, List structTypes) + public TypedModule(List functionPrototypes, List structTypes, List imports) { FunctionPrototypes = functionPrototypes; StructTypes = structTypes; + Imports = imports; } - public List FunctionPrototypes { get; set; } - public List StructTypes { get; set; } + public List FunctionPrototypes { get; } + public List StructTypes { get; } + public List Imports { get; } } \ No newline at end of file diff --git a/examples/playgroud/main.nub b/examples/playgroud/main.nub index d3c4d54..6608812 100644 --- a/examples/playgroud/main.nub +++ b/examples/playgroud/main.nub @@ -16,25 +16,7 @@ struct Human extern "main" func main(argc: i64, argv: [?]^i8): i64 { - let x: &Human = { - age = 23 - name = { - first = "oliver" - last = "stene" - } - } - - let z: Human = { - age = 23 - name = { - first = "oliver" - last = "stene" - } - } - - test(x) - - let y = x + let x: [2]Human = [{}, {}] return 0 } diff --git a/runtime/ref.c b/runtime/ref.c index 17ab78b..cdcdde8 100644 --- a/runtime/ref.c +++ b/runtime/ref.c @@ -7,6 +7,7 @@ void *rc_alloc(size_t size, void (*destructor)(void *self)) { printf("rc_alloc %zu bytes\n", size); ref_header *header = malloc(sizeof(ref_header) + size); + memset(header, 0, size); if (!header) { exit(69); @@ -20,6 +21,9 @@ void *rc_alloc(size_t size, void (*destructor)(void *self)) void rc_retain(void *obj) { + if (!obj) + return; + printf("rc_retain\n"); ref_header *header = ((ref_header *)obj) - 1; header->ref_count++; @@ -27,6 +31,9 @@ void rc_retain(void *obj) void rc_release(void *obj) { + if (!obj) + return; + ref_header *header = ((ref_header *)obj) - 1; printf("rc_release\n"); if (--header->ref_count == 0)