From 272ea33616fb6204c3d7fdb267b9eadf80bae411 Mon Sep 17 00:00:00 2001 From: nub31 Date: Fri, 27 Feb 2026 18:26:10 +0100 Subject: [PATCH] ... --- compiler/Generator.cs | 285 +++++++++++++++++++++++------------------ compiler/Parser.cs | 27 ++-- compiler/Program.cs | 7 +- examples/build.sh | 6 +- examples/math/math.nub | 4 + 5 files changed, 185 insertions(+), 144 deletions(-) diff --git a/compiler/Generator.cs b/compiler/Generator.cs index 3fec29c..c3a5b3b 100644 --- a/compiler/Generator.cs +++ b/compiler/Generator.cs @@ -20,123 +20,12 @@ public class Generator private readonly List functions; private readonly ModuleGraph moduleGraph; private readonly bool compileLib; - private readonly IndentedTextWriter writer = new(); + private IndentedTextWriter writer = new(); + private HashSet referencedTypes = new(); + private readonly HashSet emittedTypes = new(); private string Emit() { - writer.WriteLine(""" - #include - #include - #include - #include - #include - - struct nub_core_string - { - const char *data; - int length; - }; - """); - - writer.WriteLine(); - - foreach (var module in moduleGraph.GetModules()) - { - foreach (var (name, info) in module.GetTypes()) - { - switch (info) - { - case Module.TypeInfoStruct s: - writer.WriteLine($"struct {NameMangler.Mangle(module.Name, name, NubTypeStruct.Get(module.Name, name))};"); - break; - case Module.TypeInfoEnum e: - writer.WriteLine($"struct {NameMangler.Mangle(module.Name, name, NubTypeStruct.Get(module.Name, name))};"); - break; - } - } - } - - foreach (var module in moduleGraph.GetModules()) - { - foreach (var (name, info) in module.GetTypes()) - { - switch (info) - { - case Module.TypeInfoStruct s: - { - writer.WriteLine(); - writer.Write("struct "); - - if (s.Packed) - writer.Write("__attribute__((__packed__)) "); - - writer.WriteLine(NameMangler.Mangle(module.Name, name, NubTypeStruct.Get(module.Name, name))); - writer.WriteLine("{"); - using (writer.Indent()) - { - foreach (var field in s.Fields) - { - writer.WriteLine($"{CType(field.Type, field.Name)};"); - } - } - writer.WriteLine("};"); - break; - } - case Module.TypeInfoEnum e: - { - writer.WriteLine(); - writer.Write($"struct {NameMangler.Mangle(module.Name, name, NubTypeEnum.Get(module.Name, name))}"); - writer.WriteLine("{"); - using (writer.Indent()) - { - writer.WriteLine("uint32_t tag;"); - writer.WriteLine("union"); - writer.WriteLine("{"); - using (writer.Indent()) - { - foreach (var variant in e.Variants) - { - writer.WriteLine($"{CType(variant.Type, variant.Name)};"); - } - } - writer.WriteLine("};"); - } - writer.WriteLine("};"); - break; - } - } - } - } - - writer.WriteLine(); - - foreach (var module in moduleGraph.GetModules()) - { - foreach (var (name, info) in module.GetIdentifiers()) - { - if (info.Type is NubTypeFunc fn) - { - switch (info.Kind) - { - case Module.DefinitionKind.External: - writer.Write("extern "); - break; - case Module.DefinitionKind.Internal: - writer.Write("static "); - break; - } - - writer.WriteLine($"{CType(fn.ReturnType, info.MangledName)}({string.Join(", ", fn.Parameters.Select(p => CType(p)))});"); - } - else - { - writer.WriteLine($"{CType(info.Type, info.MangledName)};"); - } - } - } - - writer.WriteLine(); - if (!compileLib) { if (!moduleGraph.TryResolveIdentifier("main", "main", true, out var info)) @@ -172,7 +61,155 @@ public class Generator writer.WriteLine(); } - return writer.ToString(); + var implementations = writer.ToString(); + + writer = new IndentedTextWriter(); + + writer.WriteLine(""" + #include + #include + #include + #include + #include + + """); + + while (referencedTypes.Count != 0) + { + var type = referencedTypes.ElementAt(0); + EmitTypeDefinitionIfNotEmitted(type); + referencedTypes.Remove(type); + } + + foreach (var module in moduleGraph.GetModules()) + { + foreach (var (name, info) in module.GetIdentifiers()) + { + switch (info.Kind) + { + case Module.DefinitionKind.External: + writer.Write("extern "); + break; + case Module.DefinitionKind.Internal: + writer.Write("static "); + break; + } + + if (info.Type is NubTypeFunc fn) + writer.WriteLine($"{CType(fn.ReturnType, info.MangledName)}({string.Join(", ", fn.Parameters.Select(p => CType(p)))});"); + else + writer.WriteLine($"{CType(info.Type, info.MangledName)};"); + } + } + + var header = writer.ToString(); + + return $"{header}\n{implementations}"; + } + + private void EmitTypeDefinitionIfNotEmitted(NubType type) + { + if (emittedTypes.Contains(type)) + return; + + emittedTypes.Add(type); + + switch (type) + { + case NubTypeString stringType: + { + writer.WriteLine($"struct {NameMangler.Mangle("core", "string", stringType)}"); + writer.WriteLine("{"); + using (writer.Indent()) + { + writer.WriteLine("const char *data;"); + writer.WriteLine("size_t length;"); + } + writer.WriteLine("};"); + writer.WriteLine(); + 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) + EmitTypeDefinitionIfNotEmitted(field.Type); + + writer.Write("struct "); + + if (structInfo.Packed) + writer.Write("__attribute__((__packed__)) "); + + writer.WriteLine(NameMangler.Mangle(structType.Module, structType.Name, structType)); + writer.WriteLine("{"); + using (writer.Indent()) + { + foreach (var field in structInfo.Fields) + { + writer.WriteLine($"{CType(field.Type, field.Name)};"); + } + } + writer.WriteLine("};"); + writer.WriteLine(); + + break; + } + case NubTypeAnonymousStruct anonymousStructType: + { + foreach (var field in anonymousStructType.Fields) + EmitTypeDefinitionIfNotEmitted(field.Type); + + writer.WriteLine($"struct {NameMangler.Mangle("anonymous", "struct", anonymousStructType)}"); + writer.WriteLine("{"); + using (writer.Indent()) + { + foreach (var field in anonymousStructType.Fields) + { + writer.WriteLine($"{CType(field.Type, field.Name)};"); + } + } + writer.WriteLine("};"); + writer.WriteLine(); + + break; + } + case NubTypeEnum enumType: + { + if (!moduleGraph.TryResolveType(enumType.Module, enumType.Name, true, out var info) || info is not Module.TypeInfoEnum enumInfo) + throw new UnreachableException(); + + foreach (var variant in enumInfo.Variants) + EmitTypeDefinitionIfNotEmitted(variant.Type); + + writer.WriteLine($"struct {NameMangler.Mangle(enumType.Module, enumType.Name, enumType)}"); + writer.WriteLine("{"); + using (writer.Indent()) + { + writer.WriteLine("uint32_t tag;"); + writer.WriteLine("union"); + writer.WriteLine("{"); + using (writer.Indent()) + { + foreach (var variant in enumInfo.Variants) + { + writer.WriteLine($"{CType(variant.Type, variant.Name)};"); + } + } + writer.WriteLine("};"); + } + writer.WriteLine("};"); + writer.WriteLine(); + + break; + } + case NubTypeEnumVariant variantType: + { + EmitTypeDefinitionIfNotEmitted(variantType.EnumType); + break; + } + } } private void EmitStatement(TypedNodeStatement node) @@ -235,7 +272,7 @@ public class Generator private void EmitStatementVariableDeclaration(TypedNodeStatementVariableDeclaration statement) { var value = EmitExpression(statement.Value); - writer.WriteLine($"{CType(statement.Type)} {statement.Name.Ident} = {value};"); + writer.WriteLine($"{CType(statement.Type, statement.Name.Ident)} = {value};"); } private void EmitStatementAssignment(TypedNodeStatementAssignment statement) @@ -301,14 +338,16 @@ public class Generator { foreach (var @case in statement.Cases) { + var variantInfo = enumInfo.Variants.First(x => x.Name == @case.Variant.Ident); var tag = enumInfo.Variants.ToList().FindIndex(x => x.Name == @case.Variant.Ident); writer.WriteLine($"case {tag}:"); writer.WriteLine("{"); using (writer.Indent()) { - writer.WriteLine($"auto {@case.VariableName.Ident} = {target}.{@case.Variant.Ident};"); + writer.WriteLine($"{CType(variantInfo.Type, @case.VariableName.Ident)} = {target}.{@case.Variant.Ident};"); EmitStatement(@case.Body); + writer.WriteLine("break;"); } writer.WriteLine("}"); } @@ -324,7 +363,7 @@ public class Generator TypedNodeExpressionUnary expression => EmitExpressionUnary(expression), TypedNodeExpressionBoolLiteral expression => expression.Value.Value ? "true" : "false", TypedNodeExpressionIntLiteral expression => expression.Value.Value.ToString(), - TypedNodeExpressionStringLiteral expression => $"(struct nub_core_string){{ \"{expression.Value.Value}\", {expression.Value.Value.Length} }}", + TypedNodeExpressionStringLiteral expression => $"({CType(expression.Type)}){{ \"{expression.Value.Value}\", {expression.Value.Value.Length} }}", TypedNodeExpressionStructLiteral expression => EmitExpressionStructLiteral(expression), TypedNodeExpressionEnumLiteral expression => EmitExpressionEnumLiteral(expression), TypedNodeExpressionMemberAccess expression => EmitExpressionMemberAccess(expression), @@ -424,8 +463,10 @@ public class Generator return $"{name}({string.Join(", ", parameterValues)})"; } - private string CType(NubType node, string? varName = null) + public string CType(NubType node, string? varName = null) { + referencedTypes.Add(node); + return node switch { NubTypeVoid => "void" + (varName != null ? $" {varName}" : ""), @@ -437,15 +478,15 @@ public class Generator NubTypeSInt type => $"int{type.Width}_t" + (varName != null ? $" {varName}" : ""), NubTypeUInt type => $"uint{type.Width}_t" + (varName != null ? $" {varName}" : ""), NubTypePointer type => CType(type.To) + (varName != null ? $" *{varName}" : "*"), - NubTypeString => "struct nub_core_string" + (varName != null ? $" {varName}" : ""), + NubTypeString type => $"struct {NameMangler.Mangle("core", "string", type)}" + (varName != null ? $" {varName}" : ""), NubTypeFunc type => $"{CType(type.ReturnType)} (*{varName})({string.Join(", ", type.Parameters.Select(p => CType(p)))})", _ => throw new ArgumentOutOfRangeException(nameof(node), node, null) }; } - private string CTypeAnonymousStruct(NubTypeAnonymousStruct type, string? varName) + private static string CTypeAnonymousStruct(NubTypeAnonymousStruct type, string? varName) { - return $"struct {{ {string.Join(' ', type.Fields.Select(x => $"{CType(x.Type)} {x.Name};"))} }}{(varName != null ? $" {varName}" : "")}"; + return $"struct {NameMangler.Mangle("anonymous", "struct", type)}{(varName != null ? $" {varName}" : "")}"; } } diff --git a/compiler/Parser.cs b/compiler/Parser.cs index 90defac..fdbe772 100644 --- a/compiler/Parser.cs +++ b/compiler/Parser.cs @@ -53,23 +53,20 @@ public class Parser Dictionary modifiers = []; - while (true) + while (Peek() is TokenKeyword keyword) { - if (Peek() is TokenKeyword keyword) + switch (keyword.Keyword) { - switch (keyword.Keyword) - { - case Keyword.Export: - Next(); - modifiers[Keyword.Export] = keyword; - break; - case Keyword.Packed: - Next(); - modifiers[Keyword.Packed] = keyword; - break; - default: - goto modifier_done; - } + case Keyword.Export: + Next(); + modifiers[Keyword.Export] = keyword; + break; + case Keyword.Packed: + Next(); + modifiers[Keyword.Packed] = keyword; + break; + default: + goto modifier_done; } } diff --git a/compiler/Program.cs b/compiler/Program.cs index 7c3557e..39a6ca3 100644 --- a/compiler/Program.cs +++ b/compiler/Program.cs @@ -119,8 +119,6 @@ foreach (var ast in asts) } } -var output = Generator.Emit(functions, moduleGraph, compileLib); - if (Directory.Exists(".build")) { CleanDirectory(".build"); @@ -130,16 +128,17 @@ else Directory.CreateDirectory(".build"); } +var output = Generator.Emit(functions, moduleGraph, compileLib); +File.WriteAllText(".build/out.c", output); + if (compileLib) { - File.WriteAllText(".build/out.c", output); Process.Start("gcc", ["-Og", "-fvisibility=hidden", "-fno-builtin", "-c", "-o", ".build/out.o", ".build/out.c", .. archivePaths]).WaitForExit(); Process.Start("ar", ["rcs", ".build/out.a", ".build/out.o"]).WaitForExit(); NubLib.Pack(".build/out.nublib", ".build/out.a", Manifest.Create(moduleGraph)); } else { - File.WriteAllText(".build/out.c", output); Process.Start("gcc", ["-Og", "-fvisibility=hidden", "-fno-builtin", "-o", ".build/out", ".build/out.c", .. archivePaths]).WaitForExit(); } diff --git a/examples/build.sh b/examples/build.sh index 8d6f5ab..66910db 100755 --- a/examples/build.sh +++ b/examples/build.sh @@ -2,9 +2,9 @@ set -e pushd math dotnet run --project ../../compiler math.nub --type=lib -pushd .build -unzip out.nublib -popd +# pushd .build +# unzip out.nublib +# popd popd pushd program diff --git a/examples/math/math.nub b/examples/math/math.nub index 0d2b1e1..e7e2daf 100644 --- a/examples/math/math.nub +++ b/examples/math/math.nub @@ -15,8 +15,12 @@ export enum Message { Move: Pos } +let x: i32 + export func add(a: i32 b: i32): i32 { + let x = "test" + let msg: Message = enum Message::Move { x = 10 y = 10