WIP: dev #1
@@ -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}" : "")}";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -53,9 +53,7 @@ public class Parser
|
||||
|
||||
Dictionary<Keyword, TokenKeyword> modifiers = [];
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (Peek() is TokenKeyword keyword)
|
||||
while (Peek() is TokenKeyword keyword)
|
||||
{
|
||||
switch (keyword.Keyword)
|
||||
{
|
||||
@@ -71,7 +69,6 @@ public class Parser
|
||||
goto modifier_done;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
modifier_done:
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user