This commit is contained in:
nub31
2025-10-29 15:14:13 +01:00
parent 34a44f80a8
commit bf4c8838c6
8 changed files with 189 additions and 74 deletions

View File

@@ -48,39 +48,13 @@ Directory.CreateDirectory(".build");
var typedModules = modules.Select(x => (x.Key, TypedModule.FromModule(x.Key, x.Value, modules))).ToDictionary(); var typedModules = modules.Select(x => (x.Key, TypedModule.FromModule(x.Key, x.Value, modules))).ToDictionary();
var moduleHeaders = new List<string>(); Directory.CreateDirectory(Path.Combine(".build", "modules"));
var commonHeaderOut = Path.Combine(".build", "runtime.h");
File.WriteAllText(commonHeaderOut, """
#include <stddef.h>
void *rc_alloc(size_t size, void (*destructor)(void *self));
void rc_retain(void *obj);
void rc_release(void *obj);
typedef struct
{
unsigned long long length;
char *data;
} nub_string;
typedef struct
{
unsigned long long length;
void *data;
} nub_slice;
""");
moduleHeaders.Add(commonHeaderOut);
foreach (var typedModule in typedModules) foreach (var typedModule in typedModules)
{ {
var header = HeaderGenerator.Generate(typedModule.Key, typedModule.Value); var header = HeaderGenerator.Generate(typedModule.Key, typedModule.Value);
var headerOut = Path.Combine(".build", "modules", typedModule.Key + ".h"); var headerOut = Path.Combine(Path.Combine(".build", "modules"), typedModule.Key + ".h");
Directory.CreateDirectory(Path.Combine(".build", "modules"));
File.WriteAllText(headerOut, header); File.WriteAllText(headerOut, header);
moduleHeaders.Add(headerOut);
} }
for (var i = 0; i < args.Length; i++) for (var i = 0; i < args.Length; i++)
@@ -106,7 +80,7 @@ foreach (var cPath in cPaths)
{ {
var objectPath = Path.ChangeExtension(cPath, "o"); var objectPath = Path.ChangeExtension(cPath, "o");
using var compileProcess = Process.Start("clang", [ using var compileProcess = Process.Start("clang", [
..moduleHeaders.SelectMany(x => new[] { "-include", x }), "-I.build",
"-ffreestanding", "-std=c23", "-ffreestanding", "-std=c23",
"-g", "-c", "-g", "-c",
"-o", objectPath, "-o", objectPath,

View File

@@ -19,7 +19,8 @@ public static class CType
NubConstArrayType a => CreateConstArrayType(a, variableName, constArraysAsPointers), NubConstArrayType a => CreateConstArrayType(a, variableName, constArraysAsPointers),
NubArrayType a => CreateArrayType(a, variableName), NubArrayType a => CreateArrayType(a, variableName),
NubFuncType f => CreateFuncType(f, variableName), NubFuncType f => CreateFuncType(f, variableName),
NubStructType s => $"{s.Module}_{s.Name}_{NameMangler.Mangle(s)}" + (variableName != null ? $" {variableName}" : ""), // NubStructType s => $"{s.Module}_{s.Name}_{NameMangler.Mangle(s)}" + (variableName != null ? $" {variableName}" : ""),
NubStructType s => $"{s.Module}_{s.Name}" + (variableName != null ? $" {variableName}" : ""),
_ => throw new NotSupportedException($"C type generation not supported for: {type}") _ => throw new NotSupportedException($"C type generation not supported for: {type}")
}; };
} }
@@ -60,12 +61,12 @@ public static class CType
return baseType + "*" + (varName != null ? $" {varName}" : ""); return baseType + "*" + (varName != null ? $" {varName}" : "");
} }
private static string CreateConstArrayType(NubConstArrayType arr, string? varName, bool inStructDef) private static string CreateConstArrayType(NubConstArrayType arr, string? varName, bool constArraysAsPointers)
{ {
var elementType = Create(arr.ElementType); var elementType = Create(arr.ElementType);
// Treat const arrays as pointers unless in a struct definition // Treat const arrays as pointers unless in a struct definition
if (!inStructDef) if (constArraysAsPointers)
{ {
return elementType + "*" + (varName != null ? $" {varName}" : ""); return elementType + "*" + (varName != null ? $" {varName}" : "");
} }

View File

@@ -38,6 +38,34 @@ public class Generator
public string Emit() public string Emit()
{ {
foreach (var importNode in _compilationUnit.OfType<ImportNode>())
{
_writer.WriteLine($"#include <modules/{importNode.NameToken.Value}.h>");
}
_writer.WriteLine($"#include <modules/{GetModuleName()}.h>");
_writer.WriteLine("""
#include <stddef.h>
void *rc_alloc(size_t size, void (*destructor)(void *self));
void rc_retain(void *obj);
void rc_release(void *obj);
typedef struct
{
unsigned long long length;
char *data;
} nub_string;
typedef struct
{
unsigned long long length;
void *data;
} nub_slice;
""");
foreach (var structType in _compilationUnit.OfType<StructNode>()) foreach (var structType in _compilationUnit.OfType<StructNode>())
{ {
_writer.WriteLine($"void {CType.Create(structType.StructType)}_create({CType.Create(structType.StructType)} *self)"); _writer.WriteLine($"void {CType.Create(structType.StructType)}_create({CType.Create(structType.StructType)} *self)");
@@ -50,6 +78,7 @@ public class Generator
{ {
var value = EmitExpression(field.Value); var value = EmitExpression(field.Value);
_writer.WriteLine($"self->{field.NameToken.Value} = {value}"); _writer.WriteLine($"self->{field.NameToken.Value} = {value}");
EmitConstructor($"self->{field.NameToken.Value}", field.Type);
} }
} }
} }
@@ -65,7 +94,18 @@ public class Generator
{ {
if (field.Type is NubRefType) if (field.Type is NubRefType)
{ {
_writer.WriteLine($"rc_release(self->{field.NameToken.Value});"); _writer.WriteLine($"if (self->{field.NameToken.Value})");
_writer.WriteLine("{");
using (_writer.Indent())
{
EmitDestructor($"self->{field.NameToken.Value}", field.Type);
}
_writer.WriteLine("}");
}
else
{
EmitDestructor($"self->{field.NameToken.Value}", field.Type);
} }
} }
} }
@@ -113,6 +153,7 @@ public class Generator
private void EmitStatement(StatementNode statementNode) private void EmitStatement(StatementNode statementNode)
{ {
EmitLine(statementNode.Tokens.FirstOrDefault()); EmitLine(statementNode.Tokens.FirstOrDefault());
switch (statementNode) switch (statementNode)
{ {
case AssignmentNode assignmentNode: case AssignmentNode assignmentNode:
@@ -167,10 +208,10 @@ public class Generator
private void EmitLine(Token? token) private void EmitLine(Token? token)
{ {
if (token == null) return; // if (token == null) return;
var file = token.Span.FilePath; // var file = token.Span.FilePath;
var line = token.Span.Start.Line; // var line = token.Span.Start.Line;
_writer.WriteLine($"#line {line} \"{file}\""); // _writer.WriteLine($"#line {line} \"{file}\"");
} }
private void EmitAssignment(AssignmentNode assignmentNode) private void EmitAssignment(AssignmentNode assignmentNode)
@@ -181,7 +222,6 @@ public class Generator
if (assignmentNode.Target.Type is NubRefType) if (assignmentNode.Target.Type is NubRefType)
{ {
_writer.WriteLine($"rc_retain({value});"); _writer.WriteLine($"rc_retain({value});");
Scope.Defer(() => _writer.WriteLine($"rc_release({value});"));
_writer.WriteLine($"rc_release({target});"); _writer.WriteLine($"rc_release({target});");
} }
@@ -304,17 +344,18 @@ public class Generator
private void EmitVariableDeclaration(VariableDeclarationNode variableDeclarationNode) private void EmitVariableDeclaration(VariableDeclarationNode variableDeclarationNode)
{ {
Scope.AddVariable(variableDeclarationNode.NameToken.Value, variableDeclarationNode.Type);
if (variableDeclarationNode.Assignment != null) if (variableDeclarationNode.Assignment != null)
{ {
var value = EmitExpression(variableDeclarationNode.Assignment); var value = EmitExpression(variableDeclarationNode.Assignment);
_writer.WriteLine($"{CType.Create(variableDeclarationNode.Type, variableDeclarationNode.NameToken.Value)} = {value};");
if (variableDeclarationNode.Type is NubRefType) if (variableDeclarationNode.Type is NubRefType)
{ {
_writer.WriteLine($"rc_retain({value});"); _writer.WriteLine($"rc_retain({variableDeclarationNode.NameToken.Value});");
Scope.Defer(() => _writer.WriteLine($"rc_release({value});"));
} }
_writer.WriteLine($"{CType.Create(variableDeclarationNode.Type, variableDeclarationNode.NameToken.Value)} = {value};");
} }
else else
{ {
@@ -444,14 +485,18 @@ public class Generator
private string EmitConstArrayInitializer(ConstArrayInitializerNode arrayInitializerNode) private string EmitConstArrayInitializer(ConstArrayInitializerNode arrayInitializerNode)
{ {
var values = new List<string>(); var arrayType = (NubConstArrayType)arrayInitializerNode.Type;
foreach (var value in arrayInitializerNode.Values)
var tmp = NewTmp();
_writer.WriteLine($"{CType.Create(arrayType.ElementType)} {tmp}[{arrayType.Size}] = {{0}};");
for (var i = 0; i < arrayInitializerNode.Values.Count; i++)
{ {
values.Add(EmitExpression(value)); var valueName = EmitExpression(arrayInitializerNode.Values[i]);
_writer.WriteLine($"{tmp}[{i}] = {valueName};");
} }
var arrayType = (NubConstArrayType)arrayInitializerNode.Type; return tmp;
return $"({CType.Create(arrayType.ElementType)}[{arrayType.Size}]){{{string.Join(", ", values)}}}";
} }
private string EmitDereference(DereferenceNode dereferenceNode) private string EmitDereference(DereferenceNode dereferenceNode)
@@ -543,13 +588,16 @@ public class Generator
_writer.WriteLine($"{CType.Create(type)} {tmp} = ({CType.Create(type)})rc_alloc(sizeof({CType.Create(structType)}), (void (*)(void *)){CType.Create(structType)}_destroy);"); _writer.WriteLine($"{CType.Create(type)} {tmp} = ({CType.Create(type)})rc_alloc(sizeof({CType.Create(structType)}), (void (*)(void *)){CType.Create(structType)}_destroy);");
Scope.Defer(() => _writer.WriteLine($"rc_release({tmp});")); Scope.Defer(() => _writer.WriteLine($"rc_release({tmp});"));
_writer.WriteLine($"*{tmp} = ({CType.Create(structType)}){{{0}}};"); EmitConstructor(tmp, structType);
_writer.WriteLine($"{CType.Create(structType)}_create({tmp});");
foreach (var initializer in refStructInitializerNode.Initializers) foreach (var initializer in refStructInitializerNode.Initializers)
{ {
var value = EmitExpression(initializer.Value); var value = EmitExpression(initializer.Value);
_writer.WriteLine($"{tmp}->{initializer.Key} = {value};"); _writer.WriteLine($"{tmp}->{initializer.Key} = {value};");
if (initializer.Value.Type is NubRefType)
{
_writer.WriteLine($"rc_retain({tmp}->{initializer.Key});");
}
} }
return tmp; return tmp;
@@ -582,7 +630,7 @@ public class Generator
var tmp = NewTmp(); var tmp = NewTmp();
_writer.WriteLine($"{CType.Create(structType)} {tmp} = ({CType.Create(structType)}){{0}};"); _writer.WriteLine($"{CType.Create(structType)} {tmp} = ({CType.Create(structType)}){{0}};");
_writer.WriteLine($"{CType.Create(structType)}_create(&{tmp});"); EmitConstructor($"&{tmp}", structType);
foreach (var initializer in structInitializerNode.Initializers) foreach (var initializer in structInitializerNode.Initializers)
{ {
@@ -650,16 +698,82 @@ public class Generator
foreach (var statementNode in blockNode.Statements) foreach (var statementNode in blockNode.Statements)
{ {
EmitStatement(statementNode); EmitStatement(statementNode);
if (statementNode != blockNode.Statements.Last())
{
_writer.WriteLine();
}
} }
} }
private void EmitScopeCleanup() private void EmitScopeCleanup()
{ {
if (Scope.IsTerminated())
{
return;
}
Scope.Terminate();
var deferredStack = Scope.GetDeferred(); var deferredStack = Scope.GetDeferred();
while (deferredStack.TryPop(out var deferred)) while (deferredStack.TryPop(out var deferred))
{ {
deferred.Invoke(); deferred.Invoke();
} }
var variables = Scope.GetVariables();
while (variables.TryPop(out var variable))
{
EmitDestructor(variable.Ident, variable.Type);
}
}
private void EmitConstructor(string target, NubType type)
{
switch (type)
{
case NubStructType structType:
{
_writer.WriteLine($"{CType.Create(structType)}_create({target});");
break;
}
case NubRefType:
{
_writer.WriteLine($"rc_retain({target});");
break;
}
}
}
private void EmitDestructor(string target, NubType type)
{
switch (type)
{
case NubStructType structType:
{
_writer.WriteLine($"{CType.Create(structType)}_destroy({target});");
break;
}
case NubConstArrayType constArrayType:
{
var index = NewTmp();
_writer.WriteLine($"for (unsigned long long {index} = 0; {index} < {constArrayType.Size}; ++{index})");
_writer.WriteLine("{");
using (_writer.Indent())
{
EmitDestructor($"&({target}[{index}])", constArrayType.ElementType);
}
_writer.WriteLine("}");
break;
}
case NubRefType:
{
_writer.WriteLine($"rc_release({target});");
break;
}
}
} }
private ScopeDisposer BeginScope() private ScopeDisposer BeginScope()
@@ -678,9 +792,24 @@ public class Generator
} }
} }
public class Variable(string ident, NubType type)
{
public string Ident { get; } = ident;
public NubType Type { get; } = type;
}
public class Scope public class Scope
{ {
private bool _hasTerminated = false;
private readonly List<Action> _deferred = []; private readonly List<Action> _deferred = [];
private readonly List<Variable> _variables = [];
public void Terminate()
{
_hasTerminated = true;
}
public bool IsTerminated() => _hasTerminated;
public void Defer(Action action) public void Defer(Action action)
{ {
@@ -688,4 +817,11 @@ public class Scope
} }
public Stack<Action> GetDeferred() => new(_deferred); public Stack<Action> GetDeferred() => new(_deferred);
public void AddVariable(string ident, NubType type)
{
_variables.Add(new Variable(ident, type));
}
public Stack<Variable> GetVariables() => new(_variables);
} }

View File

@@ -1,4 +1,3 @@
using NubLang.Ast;
using NubLang.Syntax; using NubLang.Syntax;
namespace NubLang.Generation; namespace NubLang.Generation;
@@ -14,6 +13,11 @@ public static class HeaderGenerator
{ {
var writer = new IndentedTextWriter(); var writer = new IndentedTextWriter();
foreach (var import in module.Imports)
{
writer.WriteLine($"#include \"{import}.h\"");
}
writer.WriteLine(); writer.WriteLine();
foreach (var structType in module.StructTypes) foreach (var structType in module.StructTypes)

View File

@@ -48,4 +48,13 @@ public sealed class Module
.Where(x => x.Exported || includePrivate) .Where(x => x.Exported || includePrivate)
.ToList(); .ToList();
} }
public List<string> Imports()
{
return _definitions
.OfType<ImportSyntax>()
.Select(x => x.NameToken.Value)
.Distinct()
.ToList();
}
} }

View File

@@ -36,15 +36,17 @@ public sealed class TypedModule
structTypes.Add(new NubStructType(name, structSyntax.NameToken.Value, fields)); structTypes.Add(new NubStructType(name, structSyntax.NameToken.Value, fields));
} }
return new TypedModule(functionPrototypes, structTypes); return new TypedModule(functionPrototypes, structTypes, module.Imports());
} }
public TypedModule(List<FuncPrototypeNode> functionPrototypes, List<NubStructType> structTypes) public TypedModule(List<FuncPrototypeNode> functionPrototypes, List<NubStructType> structTypes, List<string> imports)
{ {
FunctionPrototypes = functionPrototypes; FunctionPrototypes = functionPrototypes;
StructTypes = structTypes; StructTypes = structTypes;
Imports = imports;
} }
public List<FuncPrototypeNode> FunctionPrototypes { get; set; } public List<FuncPrototypeNode> FunctionPrototypes { get; }
public List<NubStructType> StructTypes { get; set; } public List<NubStructType> StructTypes { get; }
public List<string> Imports { get; }
} }

View File

@@ -16,25 +16,7 @@ struct Human
extern "main" func main(argc: i64, argv: [?]^i8): i64 extern "main" func main(argc: i64, argv: [?]^i8): i64
{ {
let x: &Human = { let x: [2]Human = [{}, {}]
age = 23
name = {
first = "oliver"
last = "stene"
}
}
let z: Human = {
age = 23
name = {
first = "oliver"
last = "stene"
}
}
test(x)
let y = x
return 0 return 0
} }

View File

@@ -7,6 +7,7 @@ void *rc_alloc(size_t size, void (*destructor)(void *self))
{ {
printf("rc_alloc %zu bytes\n", size); printf("rc_alloc %zu bytes\n", size);
ref_header *header = malloc(sizeof(ref_header) + size); ref_header *header = malloc(sizeof(ref_header) + size);
memset(header, 0, size);
if (!header) if (!header)
{ {
exit(69); exit(69);
@@ -20,6 +21,9 @@ void *rc_alloc(size_t size, void (*destructor)(void *self))
void rc_retain(void *obj) void rc_retain(void *obj)
{ {
if (!obj)
return;
printf("rc_retain\n"); printf("rc_retain\n");
ref_header *header = ((ref_header *)obj) - 1; ref_header *header = ((ref_header *)obj) - 1;
header->ref_count++; header->ref_count++;
@@ -27,6 +31,9 @@ void rc_retain(void *obj)
void rc_release(void *obj) void rc_release(void *obj)
{ {
if (!obj)
return;
ref_header *header = ((ref_header *)obj) - 1; ref_header *header = ((ref_header *)obj) - 1;
printf("rc_release\n"); printf("rc_release\n");
if (--header->ref_count == 0) if (--header->ref_count == 0)