WIP: dev #1

Draft
nub31 wants to merge 103 commits from dev into master
5 changed files with 185 additions and 144 deletions
Showing only changes of commit 272ea33616 - Show all commits

View File

@@ -20,123 +20,12 @@ public class Generator
private readonly List<TypedNodeDefinitionFunc> functions; private readonly List<TypedNodeDefinitionFunc> functions;
private readonly ModuleGraph moduleGraph; private readonly ModuleGraph moduleGraph;
private readonly bool compileLib; 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() 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 (!compileLib)
{ {
if (!moduleGraph.TryResolveIdentifier("main", "main", true, out var info)) if (!moduleGraph.TryResolveIdentifier("main", "main", true, out var info))
@@ -172,7 +61,155 @@ public class Generator
writer.WriteLine(); 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) private void EmitStatement(TypedNodeStatement node)
@@ -235,7 +272,7 @@ public class Generator
private void EmitStatementVariableDeclaration(TypedNodeStatementVariableDeclaration statement) private void EmitStatementVariableDeclaration(TypedNodeStatementVariableDeclaration statement)
{ {
var value = EmitExpression(statement.Value); 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) private void EmitStatementAssignment(TypedNodeStatementAssignment statement)
@@ -301,14 +338,16 @@ public class Generator
{ {
foreach (var @case in statement.Cases) 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); var tag = enumInfo.Variants.ToList().FindIndex(x => x.Name == @case.Variant.Ident);
writer.WriteLine($"case {tag}:"); writer.WriteLine($"case {tag}:");
writer.WriteLine("{"); writer.WriteLine("{");
using (writer.Indent()) 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); EmitStatement(@case.Body);
writer.WriteLine("break;");
} }
writer.WriteLine("}"); writer.WriteLine("}");
} }
@@ -324,7 +363,7 @@ public class Generator
TypedNodeExpressionUnary expression => EmitExpressionUnary(expression), TypedNodeExpressionUnary expression => EmitExpressionUnary(expression),
TypedNodeExpressionBoolLiteral expression => expression.Value.Value ? "true" : "false", TypedNodeExpressionBoolLiteral expression => expression.Value.Value ? "true" : "false",
TypedNodeExpressionIntLiteral expression => expression.Value.Value.ToString(), 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), TypedNodeExpressionStructLiteral expression => EmitExpressionStructLiteral(expression),
TypedNodeExpressionEnumLiteral expression => EmitExpressionEnumLiteral(expression), TypedNodeExpressionEnumLiteral expression => EmitExpressionEnumLiteral(expression),
TypedNodeExpressionMemberAccess expression => EmitExpressionMemberAccess(expression), TypedNodeExpressionMemberAccess expression => EmitExpressionMemberAccess(expression),
@@ -424,8 +463,10 @@ public class Generator
return $"{name}({string.Join(", ", parameterValues)})"; 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 return node switch
{ {
NubTypeVoid => "void" + (varName != null ? $" {varName}" : ""), NubTypeVoid => "void" + (varName != null ? $" {varName}" : ""),
@@ -437,15 +478,15 @@ public class Generator
NubTypeSInt type => $"int{type.Width}_t" + (varName != null ? $" {varName}" : ""), NubTypeSInt type => $"int{type.Width}_t" + (varName != null ? $" {varName}" : ""),
NubTypeUInt type => $"uint{type.Width}_t" + (varName != null ? $" {varName}" : ""), NubTypeUInt type => $"uint{type.Width}_t" + (varName != null ? $" {varName}" : ""),
NubTypePointer type => CType(type.To) + (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)))})", NubTypeFunc type => $"{CType(type.ReturnType)} (*{varName})({string.Join(", ", type.Parameters.Select(p => CType(p)))})",
_ => throw new ArgumentOutOfRangeException(nameof(node), node, null) _ => 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,9 +53,7 @@ public class Parser
Dictionary<Keyword, TokenKeyword> modifiers = []; Dictionary<Keyword, TokenKeyword> modifiers = [];
while (true) while (Peek() is TokenKeyword keyword)
{
if (Peek() is TokenKeyword keyword)
{ {
switch (keyword.Keyword) switch (keyword.Keyword)
{ {
@@ -71,7 +69,6 @@ public class Parser
goto modifier_done; goto modifier_done;
} }
} }
}
modifier_done: modifier_done:

View File

@@ -119,8 +119,6 @@ foreach (var ast in asts)
} }
} }
var output = Generator.Emit(functions, moduleGraph, compileLib);
if (Directory.Exists(".build")) if (Directory.Exists(".build"))
{ {
CleanDirectory(".build"); CleanDirectory(".build");
@@ -130,16 +128,17 @@ else
Directory.CreateDirectory(".build"); Directory.CreateDirectory(".build");
} }
var output = Generator.Emit(functions, moduleGraph, compileLib);
File.WriteAllText(".build/out.c", output);
if (compileLib) 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("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(); Process.Start("ar", ["rcs", ".build/out.a", ".build/out.o"]).WaitForExit();
NubLib.Pack(".build/out.nublib", ".build/out.a", Manifest.Create(moduleGraph)); NubLib.Pack(".build/out.nublib", ".build/out.a", Manifest.Create(moduleGraph));
} }
else else
{ {
File.WriteAllText(".build/out.c", output);
Process.Start("gcc", ["-Og", "-fvisibility=hidden", "-fno-builtin", "-o", ".build/out", ".build/out.c", .. archivePaths]).WaitForExit(); Process.Start("gcc", ["-Og", "-fvisibility=hidden", "-fno-builtin", "-o", ".build/out", ".build/out.c", .. archivePaths]).WaitForExit();
} }

View File

@@ -2,9 +2,9 @@ set -e
pushd math pushd math
dotnet run --project ../../compiler math.nub --type=lib dotnet run --project ../../compiler math.nub --type=lib
pushd .build # pushd .build
unzip out.nublib # unzip out.nublib
popd # popd
popd popd
pushd program pushd program

View File

@@ -15,8 +15,12 @@ export enum Message {
Move: Pos Move: Pos
} }
let x: i32
export func add(a: i32 b: i32): i32 export func add(a: i32 b: i32): i32
{ {
let x = "test"
let msg: Message = enum Message::Move { let msg: Message = enum Message::Move {
x = 10 x = 10
y = 10 y = 10