From da2fa81c3947f98048dcb4da801a88bb818c8227 Mon Sep 17 00:00:00 2001 From: nub31 Date: Sat, 28 Feb 2026 02:27:44 +0100 Subject: [PATCH] ... --- compiler/Generator.cs | 201 +++++++++++++++++++++++++++++++++----- examples/program/main.nub | 21 +++- 2 files changed, 196 insertions(+), 26 deletions(-) diff --git a/compiler/Generator.cs b/compiler/Generator.cs index c3f4036..3d824c9 100644 --- a/compiler/Generator.cs +++ b/compiler/Generator.cs @@ -91,7 +91,7 @@ public class Generator writer = new IndentedTextWriter(); - writer.WriteLine(""" + writer.WriteLine($$""" #include #include #include @@ -99,8 +99,6 @@ public class Generator #include #include - #define FLAG_STRING_LITERAL 1 - """); while (referencedTypes.Count != 0) @@ -132,11 +130,48 @@ public class Generator { writer.WriteLine("char *data;"); writer.WriteLine("size_t length;"); - writer.WriteLine("uint32_t ref;"); + writer.WriteLine("int32_t ref;"); writer.WriteLine("uint32_t flags;"); } writer.WriteLine("};"); writer.WriteLine(); + + writer.WriteLine("#define FLAG_STRING_LITERAL 1"); + writer.WriteLine(); + + writer.WriteLine($"static inline void rc_inc({CType(NubTypeString.Instance, "string")})"); + writer.WriteLine("{"); + using (writer.Indent()) + { + writer.WriteLine($"string->ref += 1;"); + } + writer.WriteLine("}"); + writer.WriteLine(); + + writer.WriteLine($"static inline void rc_dec({CType(NubTypeString.Instance, "string")})"); + writer.WriteLine("{"); + using (writer.Indent()) + { + writer.WriteLine($"string->ref -= 1;"); + writer.WriteLine($"if (string->ref <= 0)"); + writer.WriteLine("{"); + using (writer.Indent()) + { + writer.WriteLine($"if ((string->flags & FLAG_STRING_LITERAL) == 0)"); + writer.WriteLine("{"); + using (writer.Indent()) + { + writer.WriteLine($"free(string->data);"); + } + writer.WriteLine("}"); + writer.WriteLine($"free(string);"); + } + writer.WriteLine("}"); + + } + writer.WriteLine("}"); + writer.WriteLine(); + break; } case NubTypeStruct structType: @@ -302,7 +337,7 @@ public class Generator var value = EmitExpression(statement.Value); EmitCopyConstructor(value, statement.Value.Type); writer.WriteLine($"{CType(statement.Type, statement.Name.Ident)} = {value};"); - scopes.Peek().Locals.Add((statement.Name.Ident, statement.Type)); + scopes.Peek().DeconstructableNames.Add((statement.Name.Ident, statement.Type)); } private void EmitStatementAssignment(TypedNodeStatementAssignment statement) @@ -397,7 +432,7 @@ public class Generator private string EmitExpression(TypedNodeExpression node) { - return node switch + var value = node switch { TypedNodeExpressionBinary expression => EmitExpressionBinary(expression), TypedNodeExpressionUnary expression => EmitExpressionUnary(expression), @@ -414,6 +449,10 @@ public class Generator TypedNodeExpressionFuncCall expression => EmitExpressionFuncCall(expression), _ => throw new ArgumentOutOfRangeException(nameof(node), node, null) }; + + var tmp = TmpName(); + writer.WriteLine($"{CType(node.Type, tmp)} = {value};"); + return tmp; } private string EmitExpressionBinary(TypedNodeExpressionBinary expression) @@ -457,7 +496,7 @@ public class Generator private string EmitExpressionStringLiteral(TypedNodeExpressionStringLiteral expression) { var name = TmpName(); - scopes.Peek().Locals.Add((name, expression.Type)); + scopes.Peek().DeconstructableNames.Add((name, expression.Type)); var variable = CType(expression.Type, name); @@ -472,21 +511,30 @@ public class Generator private string EmitExpressionStructLiteral(TypedNodeExpressionStructLiteral expression) { + var name = TmpName(); + scopes.Peek().DeconstructableNames.Add((name, expression.Type)); + var initializerValues = new Dictionary(); foreach (var initializer in expression.Initializers) { - var values = EmitExpression(initializer.Value); - initializerValues[initializer.Name.Ident] = values; + var value = EmitExpression(initializer.Value); + EmitCopyConstructor(value, initializer.Value.Type); + initializerValues[initializer.Name.Ident] = value; } var initializerStrings = initializerValues.Select(x => $".{x.Key} = {x.Value}"); - return $"({CType(expression.Type)}){{ {string.Join(", ", initializerStrings)} }}"; + writer.WriteLine($"{CType(expression.Type, name)} = ({CType(expression.Type)}){{ {string.Join(", ", initializerStrings)} }};"); + + return name; } private string EmitExpressionEnumLiteral(TypedNodeExpressionEnumLiteral expression) { + var name = TmpName(); + scopes.Peek().DeconstructableNames.Add((name, expression.Type)); + var enumVariantType = (NubTypeEnumVariant)expression.Type; if (!moduleGraph.TryResolveType(enumVariantType.EnumType.Module, enumVariantType.EnumType.Name, true, out var info)) @@ -496,8 +544,11 @@ public class Generator var tag = enumInfo.Variants.ToList().FindIndex(x => x.Name == enumVariantType.Variant); var value = EmitExpression(expression.Value); + EmitCopyConstructor(value, expression.Value.Type); - return $"({CType(expression.Type)}){{ .tag = {tag}, .{enumVariantType.Variant} = {value} }}"; + writer.WriteLine($"{CType(expression.Type, name)} = ({CType(expression.Type)}){{ .tag = {tag}, .{enumVariantType.Variant} = {value} }};"); + + return name; } private string EmitExpressionMemberAccess(TypedNodeExpressionStructMemberAccess expression) @@ -568,9 +619,9 @@ public class Generator { foreach (var scope in scopes.Reverse()) { - for (int i = scope.Locals.Count - 1; i >= 0; i--) + for (int i = scope.DeconstructableNames.Count - 1; i >= 0; i--) { - var (name, type) = scope.Locals[i]; + var (name, type) = scope.DeconstructableNames[i]; EmitCopyDestructor(name, type); } } @@ -578,9 +629,9 @@ public class Generator private void EmitCleanupCurrentScope(Scope scope) { - for (int i = scope.Locals.Count - 1; i >= 0; i--) + for (int i = scope.DeconstructableNames.Count - 1; i >= 0; i--) { - var (name, type) = scope.Locals[i]; + var (name, type) = scope.DeconstructableNames[i]; EmitCopyDestructor(name, type); } } @@ -590,8 +641,65 @@ public class Generator switch (type) { case NubTypeString: - writer.WriteLine($"{value}->ref += 1;"); + { + writer.WriteLine($"rc_inc({value});"); break; + } + case NubTypeStruct structType: + { + if (!moduleGraph.TryResolveType(structType.Module, structType.Name, true, out var info) || info is not Module.TypeInfoStruct structInfo) + throw new UnreachableException(); + + foreach (var field in structInfo.Fields) + { + EmitCopyConstructor($"{value}.{field.Name}", field.Type); + } + break; + } + case NubTypeAnonymousStruct anonymousStructType: + { + foreach (var field in anonymousStructType.Fields) + { + EmitCopyConstructor($"{value}.{field.Name}", field.Type); + } + break; + } + case NubTypeEnum enumType: + { + if (!moduleGraph.TryResolveType(enumType.Module, enumType.Name, true, out var info) || info is not Module.TypeInfoEnum enumInfo) + throw new UnreachableException(); + + writer.WriteLine($"switch ({value}.tag)"); + writer.WriteLine("{"); + using (writer.Indent()) + { + for (int i = 0; i < enumInfo.Variants.Count; i++) + { + Module.TypeInfoEnum.Variant variant = enumInfo.Variants[i]; + + writer.WriteLine($"case {i}:"); + writer.WriteLine("{"); + using (writer.Indent()) + { + EmitCopyConstructor($"{value}.{variant.Name}", variant.Type); + writer.WriteLine("break;"); + } + writer.WriteLine("}"); + } + } + writer.WriteLine("}"); + break; + } + case NubTypeEnumVariant enumVariantType: + { + if (!moduleGraph.TryResolveType(enumVariantType.EnumType.Module, enumVariantType.EnumType.Name, true, out var info) || info is not Module.TypeInfoEnum enumInfo) + throw new UnreachableException(); + + var variant = enumInfo.Variants.First(x => x.Name == enumVariantType.Variant); + + EmitCopyConstructor($"{value}.{variant.Name}", variant.Type); + break; + } } } @@ -600,22 +708,65 @@ public class Generator switch (type) { case NubTypeString: - writer.WriteLine($"{value}->ref -= 1;"); - writer.WriteLine($"if ({value}->ref == 0)"); + { + writer.WriteLine($"rc_dec({value});"); + break; + } + case NubTypeStruct structType: + { + if (!moduleGraph.TryResolveType(structType.Module, structType.Name, true, out var info) || info is not Module.TypeInfoStruct structInfo) + throw new UnreachableException(); + + foreach (var field in structInfo.Fields) + { + EmitCopyDestructor($"{value}.{field.Name}", field.Type); + } + break; + } + case NubTypeAnonymousStruct anonymousStructType: + { + foreach (var field in anonymousStructType.Fields) + { + EmitCopyDestructor($"{value}.{field.Name}", field.Type); + } + break; + } + case NubTypeEnum enumType: + { + if (!moduleGraph.TryResolveType(enumType.Module, enumType.Name, true, out var info) || info is not Module.TypeInfoEnum enumInfo) + throw new UnreachableException(); + + writer.WriteLine($"switch ({value}.tag)"); writer.WriteLine("{"); using (writer.Indent()) { - writer.WriteLine($"if (({value}->flags & FLAG_STRING_LITERAL) == 0)"); - writer.WriteLine("{"); - using (writer.Indent()) + for (int i = 0; i < enumInfo.Variants.Count; i++) { - writer.WriteLine($"free({value}->data);"); + var variant = enumInfo.Variants[i]; + + writer.WriteLine($"case {i}:"); + writer.WriteLine("{"); + using (writer.Indent()) + { + EmitCopyDestructor($"{value}.{variant.Name}", variant.Type); + writer.WriteLine("break;"); + } + writer.WriteLine("}"); } - writer.WriteLine("}"); - writer.WriteLine($"free({value});"); } writer.WriteLine("}"); break; + } + case NubTypeEnumVariant enumVariantType: + { + if (!moduleGraph.TryResolveType(enumVariantType.EnumType.Module, enumVariantType.EnumType.Name, true, out var info) || info is not Module.TypeInfoEnum enumInfo) + throw new UnreachableException(); + + var variant = enumInfo.Variants.First(x => x.Name == enumVariantType.Variant); + + EmitCopyDestructor($"{value}.{variant.Name}", variant.Type); + break; + } } } @@ -633,7 +784,7 @@ public class Generator private class Scope { - public List<(string Name, NubType Type)> Locals { get; } = []; + public List<(string Name, NubType Type)> DeconstructableNames { get; } = []; public bool Unreachable { get; set; } } } diff --git a/examples/program/main.nub b/examples/program/main.nub index 7001305..eb1593b 100644 --- a/examples/program/main.nub +++ b/examples/program/main.nub @@ -1,6 +1,25 @@ module main +extern func puts(text: ^u8) + +export func print(text: string) { + puts(text.ptr) +} + +enum Message { + Tell: string +} + func main(): i32 { - core::print("Your mom") + let x = "test" + + let y = { + abc = x + } + + let a: Message = enum Message::Tell x + + core::print(x) + return 0 } \ No newline at end of file