...
This commit is contained in:
@@ -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}" : "")}";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user