WIP: dev #1
@@ -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}" : "")}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -53,23 +53,20 @@ 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)
|
case Keyword.Export:
|
||||||
{
|
Next();
|
||||||
case Keyword.Export:
|
modifiers[Keyword.Export] = keyword;
|
||||||
Next();
|
break;
|
||||||
modifiers[Keyword.Export] = keyword;
|
case Keyword.Packed:
|
||||||
break;
|
Next();
|
||||||
case Keyword.Packed:
|
modifiers[Keyword.Packed] = keyword;
|
||||||
Next();
|
break;
|
||||||
modifiers[Keyword.Packed] = keyword;
|
default:
|
||||||
break;
|
goto modifier_done;
|
||||||
default:
|
|
||||||
goto modifier_done;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user