This commit is contained in:
nub31
2025-10-20 18:31:43 +02:00
parent 0bd52298fb
commit 34d36eb8b2
12 changed files with 313 additions and 724 deletions

View File

@@ -1,4 +1,3 @@
using System.Text;
using NubLang.Ast;
using NubLang.Syntax;
@@ -6,17 +5,14 @@ namespace NubLang.Generation;
public class Generator
{
private readonly List<DefinitionNode> _definitions;
private readonly CompilationUnit _compilationUnit;
private readonly IndentedTextWriter _writer;
private readonly Stack<List<DeferNode>> _deferStack = [];
private readonly Stack<(string Name, NubFuncType FuncType)> _funcDefs = [];
private readonly List<NubStructType> _structTypes = [];
private int _tmpIndex;
private int _funcDefIndex;
public Generator(List<DefinitionNode> definitions)
public Generator(CompilationUnit compilationUnit)
{
_definitions = definitions;
_compilationUnit = compilationUnit;
_writer = new IndentedTextWriter();
}
@@ -26,54 +22,6 @@ public class Generator
return $"_t{++_tmpIndex}";
}
private string MapType(NubType nubType)
{
return nubType switch
{
NubArrayType arrayType => MapType(arrayType.ElementType),
NubConstArrayType arrayType => MapType(arrayType.ElementType),
NubBoolType => "bool",
NubCStringType => "char",
NubFloatType floatType => floatType.Width switch
{
32 => "f32",
64 => "f64",
_ => throw new ArgumentOutOfRangeException()
},
NubFuncType funcType => MapFuncType(funcType),
NubIntType intType => (intType.Signed, intType.Width) switch
{
(false, 8) => "u8",
(false, 16) => "u16",
(false, 32) => "u32",
(false, 64) => "u64",
(true, 8) => "i8",
(true, 16) => "i16",
(true, 32) => "i32",
(true, 64) => "i64",
_ => throw new ArgumentOutOfRangeException()
},
NubPointerType pointerType => MapType(pointerType.BaseType),
NubStringType => throw new NotImplementedException(),
NubStructType structType => MapStructType(structType),
NubVoidType => "void",
_ => throw new ArgumentOutOfRangeException(nameof(nubType))
};
}
private string MapStructType(NubStructType structType)
{
_structTypes.Add(structType);
return StructName(structType.Module, structType.Name);
}
private string MapFuncType(NubFuncType funcType)
{
var name = $"_func_type_def{++_funcDefIndex}";
_funcDefs.Push((name, funcType));
return name;
}
private string MapNameWithType(NubType nubType, string name)
{
var prefix = "";
@@ -81,7 +29,7 @@ public class Generator
switch (nubType)
{
case NubCStringType or NubPointerType:
case NubCStringType or NubPointerType or NubFuncType:
prefix = "*";
break;
case NubArrayType:
@@ -92,7 +40,42 @@ public class Generator
break;
}
return $"{MapType(nubType)} {prefix}{name}{postfix}";
return $"{MapBaseType(nubType)} {prefix}{name}{postfix}";
string MapBaseType(NubType type)
{
return type switch
{
NubArrayType arrayType => MapBaseType(arrayType.ElementType),
NubConstArrayType arrayType => MapBaseType(arrayType.ElementType),
NubBoolType => "bool",
NubCStringType => "char",
NubFloatType floatType => floatType.Width switch
{
32 => "f32",
64 => "f64",
_ => throw new ArgumentOutOfRangeException()
},
NubFuncType funcType => "void",
NubIntType intType => (intType.Signed, intType.Width) switch
{
(false, 8) => "u8",
(false, 16) => "u16",
(false, 32) => "u32",
(false, 64) => "u64",
(true, 8) => "i8",
(true, 16) => "i16",
(true, 32) => "i32",
(true, 64) => "i64",
_ => throw new ArgumentOutOfRangeException()
},
NubPointerType pointerType => MapBaseType(pointerType.BaseType),
NubStringType => throw new NotImplementedException(),
NubStructType structType => StructName(structType.Module, structType.Name),
NubVoidType => "void",
_ => throw new ArgumentOutOfRangeException(nameof(type))
};
}
}
private static string FuncName(string module, string name, string? externSymbol)
@@ -105,139 +88,101 @@ public class Generator
return $"{module}_{name}";
}
private static string StructFuncName(string module, string name, string function)
{
return $"{module}_{name}_{function}";
}
public string Emit()
{
const string header = """
typedef __builtin_va_list va_list;
#define va_start(ap, last) __builtin_va_start(ap, last)
#define va_arg(ap, type) __builtin_va_arg(ap, type)
#define va_end(ap) __builtin_va_end(ap)
#define va_copy(dest, src) __builtin_va_copy(dest, src)
#define NULL ((void*)0)
typedef unsigned long size_t;
typedef unsigned long uintptr_t;
#define offsetof(type, member) __builtin_offsetof(type, member)
typedef unsigned char u8;
typedef signed char i8;
typedef unsigned short u16;
typedef signed short i16;
typedef unsigned int u32;
typedef signed int i32;
typedef unsigned long long u64;
typedef signed long long i64;
typedef float f32;
typedef double f64;
#define I8_C(x) x
#define U8_C(x) x##U
#define I16_C(x) x
#define U16_C(x) x##U
#define I32_C(x) x
#define U32_C(x) x##U
#define I64_C(x) x##LL
#define U64_C(x) x##ULL
""";
_writer.WriteLine();
var appendNewLine = false;
foreach (var funcNode in _definitions.OfType<FuncNode>())
// note(nub31): Struct definitions
foreach (var structType in _compilationUnit.ImportedStructTypes)
{
EmitLine(funcNode.Tokens.FirstOrDefault());
appendNewLine = true;
var parameters = funcNode.Signature.Parameters.Count != 0
? string.Join(", ", funcNode.Signature.Parameters.Select(x => MapNameWithType(x.Type, x.Name)))
: "void";
_writer.WriteLine("typedef struct");
_writer.WriteLine("{");
using (_writer.Indent())
{
foreach (var field in structType.Fields)
{
_writer.WriteLine($"{MapNameWithType(field.Type, field.Name)};");
}
}
var name = FuncName(funcNode.Module, funcNode.Name, funcNode.ExternSymbol);
_writer.WriteLine($"{MapNameWithType(funcNode.Signature.ReturnType, name)}({parameters});");
}
if (appendNewLine)
{
_writer.WriteLine($"}} {StructName(structType.Module, structType.Name)};");
_writer.WriteLine();
}
foreach (var structNode in _definitions.OfType<StructNode>())
// note(nub31): Forward declarations
foreach (var prototype in _compilationUnit.ImportedFunctions)
{
foreach (var structFuncNode in structNode.Functions)
{
EmitLine(structFuncNode.Tokens.FirstOrDefault());
var parameters = structFuncNode.Signature.Parameters.Count != 0
? string.Join(", ", structFuncNode.Signature.Parameters.Select(x => MapNameWithType(x.Type, x.Name)))
: "void";
EmitLine(prototype.Tokens.FirstOrDefault());
var parameters = prototype.Parameters.Count != 0
? string.Join(", ", prototype.Parameters.Select(x => MapNameWithType(x.Type, x.Name)))
: "void";
var name = StructFuncName(structNode.Module, structNode.Name, structFuncNode.Name);
_writer.WriteLine($"{MapNameWithType(structFuncNode.Signature.ReturnType, name)}({parameters})");
EmitBlock(structFuncNode.Body);
_writer.WriteLine();
}
var name = FuncName(prototype.Module, prototype.Name, prototype.ExternSymbol);
_writer.WriteLine($"{MapNameWithType(prototype.ReturnType, name)}({parameters});");
}
foreach (var funcNode in _definitions.OfType<FuncNode>())
_writer.WriteLine();
// note(nub31): Normal functions
foreach (var funcNode in _compilationUnit.Functions)
{
if (funcNode.Body == null) continue;
EmitLine(funcNode.Tokens.FirstOrDefault());
var parameters = funcNode.Signature.Parameters.Count != 0
? string.Join(", ", funcNode.Signature.Parameters.Select(x => MapNameWithType(x.Type, x.Name)))
var parameters = funcNode.Prototype.Parameters.Count != 0
? string.Join(", ", funcNode.Prototype.Parameters.Select(x => MapNameWithType(x.Type, x.Name)))
: "void";
if (funcNode.ExternSymbol == null)
if (funcNode.Prototype.ExternSymbol == null)
{
_writer.Write("static ");
}
var name = FuncName(funcNode.Module, funcNode.Name, funcNode.ExternSymbol);
_writer.WriteLine($"{MapNameWithType(funcNode.Signature.ReturnType, name)}({parameters})");
var name = FuncName(funcNode.Module, funcNode.Name, funcNode.Prototype.ExternSymbol);
_writer.WriteLine($"{MapNameWithType(funcNode.Prototype.ReturnType, name)}({parameters})");
EmitBlock(funcNode.Body);
_writer.WriteLine();
}
List<string> typedefs = [];
return $"""
typedef __builtin_va_list va_list;
while (_funcDefs.TryPop(out var funcTypeDef))
{
var returnType = MapType(funcTypeDef.FuncType.ReturnType);
var paramList = string.Join(", ", funcTypeDef.FuncType.Parameters.Select((type, i) => MapNameWithType(type, $"arg{i}")));
if (funcTypeDef.FuncType.Parameters.Count == 0)
{
paramList = "void";
}
#define va_start(ap, last) __builtin_va_start(ap, last)
#define va_arg(ap, type) __builtin_va_arg(ap, type)
#define va_end(ap) __builtin_va_end(ap)
#define va_copy(dest, src) __builtin_va_copy(dest, src)
typedefs.Add($"typedef {returnType} (*{funcTypeDef.Name})({paramList});");
}
#define NULL ((void*)0)
var structDefSb = new StringBuilder();
foreach (var structType in _structTypes)
{
structDefSb.AppendLine("typedef struct");
structDefSb.AppendLine("{");
foreach (var field in structType.Fields)
{
structDefSb.AppendLine($" {MapNameWithType(field.Type, field.Name)};");
}
typedef unsigned long size_t;
typedef unsigned long uintptr_t;
structDefSb.AppendLine($"}} {StructName(structType.Module, structType.Name)};");
structDefSb.AppendLine();
}
#define offsetof(type, member) __builtin_offsetof(type, member)
return header + structDefSb + "\n\n" + string.Join('\n', typedefs) + "\n\n" + _writer;
typedef unsigned char u8;
typedef signed char i8;
typedef unsigned short u16;
typedef signed short i16;
typedef unsigned int u32;
typedef signed int i32;
typedef unsigned long long u64;
typedef signed long long i64;
typedef float f32;
typedef double f64;
#define I8_C(x) x
#define U8_C(x) x##U
#define I16_C(x) x
#define U16_C(x) x##U
#define I32_C(x) x
#define U32_C(x) x##U
#define I64_C(x) x##LL
#define U64_C(x) x##ULL
{_writer}
""";
}
private void EmitStatement(StatementNode statementNode)
@@ -269,9 +214,6 @@ public class Generator
case StatementFuncCallNode statementFuncCallNode:
EmitStatementFuncCall(statementFuncCallNode);
break;
case StatementStructFuncCallNode statementStructFuncCallNode:
EmitStatementStructFuncCall(statementStructFuncCallNode);
break;
case VariableDeclarationNode variableDeclarationNode:
EmitVariableDeclaration(variableDeclarationNode);
break;
@@ -316,7 +258,7 @@ public class Generator
private void EmitIf(IfNode ifNode, bool elseIf = false)
{
var condition = EmitExpression(ifNode.Condition);
_writer.WriteLine($"{(elseIf ? "else" : "")} if ({condition})");
_writer.WriteLine($"{(elseIf ? "else " : "")}if ({condition})");
EmitBlock(ifNode.Body);
ifNode.Else?.Match
(
@@ -373,12 +315,6 @@ public class Generator
_writer.WriteLine($"{funcCall};");
}
private void EmitStatementStructFuncCall(StatementStructFuncCallNode statementStructFuncCallNode)
{
var structFuncCall = EmitStructFuncCall(statementStructFuncCallNode.StructFuncCall);
_writer.WriteLine($"{structFuncCall};");
}
private void EmitVariableDeclaration(VariableDeclarationNode variableDeclarationNode)
{
if (variableDeclarationNode.Assignment != null)
@@ -423,7 +359,6 @@ public class Generator
SizeBuiltinNode sizeBuiltinNode => EmitSizeBuiltin(sizeBuiltinNode),
StringLiteralNode stringLiteralNode => EmitStringLiteral(stringLiteralNode),
StructFieldAccessNode structFieldAccessNode => EmitStructFieldAccess(structFieldAccessNode),
StructFuncCallNode structFuncCallNode => EmitStructFuncCall(structFuncCallNode),
StructInitializerNode structInitializerNode => EmitStructInitializer(structInitializerNode),
UIntLiteralNode uIntLiteralNode => EmitUIntLiteral(uIntLiteralNode),
UnaryExpressionNode unaryExpressionNode => EmitUnaryExpression(unaryExpressionNode),
@@ -606,12 +541,7 @@ public class Generator
private string EmitSizeBuiltin(SizeBuiltinNode sizeBuiltinNode)
{
if (sizeBuiltinNode.TargetType is NubConstArrayType constArrayType)
{
return $"sizeof({MapType(constArrayType.ElementType)}) * {constArrayType.Size}";
}
return $"sizeof({MapType(sizeBuiltinNode.TargetType)})";
throw new NotImplementedException();
}
private string EmitStringLiteral(StringLiteralNode stringLiteralNode)
@@ -625,14 +555,6 @@ public class Generator
return $"{structExpr}.{structFieldAccessNode.Field}";
}
private string EmitStructFuncCall(StructFuncCallNode structFuncCallNode)
{
var thisParameter = EmitExpression(structFuncCallNode.StructExpression);
var name = StructFuncName(structFuncCallNode.Module, structFuncCallNode.StructName, structFuncCallNode.FuncName);
var parameterNames = structFuncCallNode.Parameters.Select(EmitExpression).ToList();
return $"{name}({thisParameter}, {string.Join(", ", parameterNames)})";
}
private string EmitStructInitializer(StructInitializerNode structInitializerNode)
{
var initValues = new List<string>();