This commit is contained in:
nub31
2026-02-27 18:26:10 +01:00
parent b7dc77cb1c
commit 272ea33616
5 changed files with 185 additions and 144 deletions

View File

@@ -20,123 +20,12 @@ public class Generator
private readonly List<TypedNodeDefinitionFunc> functions;
private readonly ModuleGraph moduleGraph;
private readonly bool compileLib;
private readonly IndentedTextWriter writer = new();
private IndentedTextWriter writer = new();
private HashSet<NubType> referencedTypes = new();
private readonly HashSet<NubType> emittedTypes = new();
private string Emit()
{
writer.WriteLine("""
#include <float.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdbool.h>
#include <stdint.h>
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 <float.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdbool.h>
#include <stdint.h>
""");
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}" : "")}";
}
}

View File

@@ -53,23 +53,20 @@ public class Parser
Dictionary<Keyword, TokenKeyword> 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;
}
}

View File

@@ -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();
}