This commit is contained in:
nub31
2025-09-11 23:34:13 +02:00
parent 0fd1af7e60
commit adcc9f3580
7 changed files with 95 additions and 31 deletions

View File

@@ -379,7 +379,7 @@ public class QBEGenerator
_labelIndex = 0; _labelIndex = 0;
_tmpIndex = 0; _tmpIndex = 0;
_writer.Write("export function "); _writer.Write(funcDef.ExternSymbol != null ? "export function " : "function ");
if (funcDef.Signature.ReturnType is not VoidTypeNode) if (funcDef.Signature.ReturnType is not VoidTypeNode)
{ {

View File

@@ -6,7 +6,7 @@ public record FuncParameterNode(string Name, TypeNode Type) : Node;
public record FuncSignatureNode(IReadOnlyList<FuncParameterNode> Parameters, TypeNode ReturnType) : Node; public record FuncSignatureNode(IReadOnlyList<FuncParameterNode> Parameters, TypeNode ReturnType) : Node;
public record FuncNode(string Module, string Name, FuncSignatureNode Signature, BlockNode? Body) : DefinitionNode(Module, Name); public record FuncNode(string Module, string Name, string? ExternSymbol, FuncSignatureNode Signature, BlockNode? Body) : DefinitionNode(Module, Name);
public record StructFieldNode(int Index, string Name, TypeNode Type, Optional<ExpressionNode> Value) : Node; public record StructFieldNode(int Index, string Name, TypeNode Type, Optional<ExpressionNode> Value) : Node;

View File

@@ -1,3 +1,4 @@
using System.Diagnostics;
using NubLang.Diagnostics; using NubLang.Diagnostics;
using NubLang.Parsing.Syntax; using NubLang.Parsing.Syntax;
using NubLang.Tokenization; using NubLang.Tokenization;
@@ -59,7 +60,11 @@ public sealed class TypeChecker
private InterfaceNode CheckInterfaceDefinition(InterfaceSyntax node) private InterfaceNode CheckInterfaceDefinition(InterfaceSyntax node)
{ {
throw new NotImplementedException(); var functions = node.Functions
.Select(function => new InterfaceFuncNode(function.Name, CheckFuncSignature(function.Signature)))
.ToList();
return new InterfaceNode(_syntaxTree.Metadata.ModuleName, node.Name, functions);
} }
private StructNode CheckStructDefinition(StructSyntax node) private StructNode CheckStructDefinition(StructSyntax node)
@@ -124,7 +129,7 @@ public sealed class TypeChecker
_funcReturnTypes.Pop(); _funcReturnTypes.Pop();
} }
return new FuncNode(_syntaxTree.Metadata.ModuleName, node.Name, CheckFuncSignature(node.Signature), body); return new FuncNode(_syntaxTree.Metadata.ModuleName, node.Name, node.ExternSymbol, CheckFuncSignature(node.Signature), body);
} }
private StatementNode CheckStatement(StatementSyntax node) private StatementNode CheckStatement(StatementSyntax node)
@@ -308,7 +313,7 @@ public sealed class TypeChecker
var parameterExpression = CheckExpression(parameter, expectedType); var parameterExpression = CheckExpression(parameter, expectedType);
if (parameterExpression.Type != expectedType) if (parameterExpression.Type != expectedType)
{ {
throw new Exception($"Parameter {i + 1} does not match the type {expectedType} for function {funcType}"); throw new TypeCheckerException(Diagnostic.Error($"Parameter {i + 1} does not match the type {expectedType} for function {funcType}").At(parameter).Build());
} }
parameters.Add(parameterExpression); parameters.Add(parameterExpression);
@@ -402,12 +407,77 @@ public sealed class TypeChecker
private StructFieldAccessNode CheckStructFieldAccess(StructFieldAccessSyntax expression) private StructFieldAccessNode CheckStructFieldAccess(StructFieldAccessSyntax expression)
{ {
throw new NotImplementedException(); var target = CheckExpression(expression.Target);
if (target.Type is not StructTypeNode structType)
{
throw new TypeCheckerException(Diagnostic
.Error($"Cannot access struct member on non-struct type {target.Type}")
.At(expression)
.Build());
}
var field = structType.Fields.FirstOrDefault(x => x.Name == expression.Member);
if (field == null)
{
throw new TypeCheckerException(Diagnostic
.Error($"Struct {target.Type} does not have a field with the name {expression.Member}")
.At(expression)
.Build());
}
return new StructFieldAccessNode(field.Type, structType, target, expression.Member);
} }
private StructInitializerNode CheckStructInitializer(StructInitializerSyntax expression, TypeNode? expectedType) private StructInitializerNode CheckStructInitializer(StructInitializerSyntax expression, TypeNode? expectedType)
{ {
throw new NotImplementedException(); StructTypeNode? structType = null;
if (expression.StructType.TryGetValue(out var customType))
{
var checkedType = ResolveType(customType);
if (checkedType is not StructTypeNode checkedStructType)
{
throw new UnreachableException("Parser fucked up");
}
structType = checkedStructType;
}
else if (expectedType is StructTypeNode expectedStructType)
{
structType = expectedStructType;
}
if (structType == null)
{
throw new TypeCheckerException(Diagnostic
.Error("Cannot get implicit type of struct")
.WithHelp("Specify struct type with struct {type_name} syntax")
.At(expression)
.Build());
}
var initializers = new Dictionary<string, ExpressionNode>();
foreach (var initializer in expression.Initializers)
{
initializers.Add(initializer.Key, CheckExpression(initializer.Value));
}
var missingFields = structType.Fields
.Where(x => !x.HasDefaultValue && !initializers.ContainsKey(x.Name))
.Select(x => x.Name)
.ToArray();
if (missingFields.Length != 0)
{
throw new TypeCheckerException(Diagnostic
.Error($"Fields {string.Join(", ", missingFields)} are not initialized")
.At(expression)
.Build());
}
return new StructInitializerNode(structType, initializers);
} }
private UnaryExpressionNode CheckUnaryExpression(UnaryExpressionSyntax expression) private UnaryExpressionNode CheckUnaryExpression(UnaryExpressionSyntax expression)
@@ -453,7 +523,7 @@ public sealed class TypeChecker
{ {
if (!_importedModules.TryGetValue(customType.Module, out var module)) if (!_importedModules.TryGetValue(customType.Module, out var module))
{ {
throw new Exception("Module not found: " + customType.Module); throw new TypeCheckerException(Diagnostic.Error($"Module {customType.Module} not found").WithHelp($"import \"{customType.Module}\"").At(customType).Build());
} }
if (customType.Module == _syntaxTree.Metadata.ModuleName) if (customType.Module == _syntaxTree.Metadata.ModuleName)

View File

@@ -1,20 +0,0 @@
module "main"
import "test"
export extern "puts" func puts(text: cstring)
struct Human
{
name: cstring
age: u64
}
func main(args: []cstring): i64
{
let me: main::Human = {
name = "Oliver"
age = 21
}
return 0
}

View File

@@ -3,8 +3,8 @@ NUBC = ../compiler/NubLang.CLI/bin/Debug/net9.0/nubc
out: .build/out.o out: .build/out.o
gcc -nostartfiles -o out x86_64.s .build/out.o gcc -nostartfiles -o out x86_64.s .build/out.o
.build/out.o: $(NUBC) main.nub .build/out.o: $(NUBC) src/main.nub src/test.nub
$(NUBC) main.nub $(NUBC) src/main.nub src/test.nub
.PHONY: $(NUBC) .PHONY: $(NUBC)
$(NUBC): $(NUBC):

14
example/src/main.nub Normal file
View File

@@ -0,0 +1,14 @@
module "main"
import "test"
export extern "puts" func puts(text: cstring)
export struct Test1
{
test2: ^test::Test2
}
extern "main" func main(args: []cstring): i64
{
return 0
}

View File

@@ -4,7 +4,7 @@
.globl _start .globl _start
_start: _start:
mov rdi, rsp mov rdi, rsp
call main.main call main
mov rdi, rax mov rdi, rax
mov rax, 60 mov rax, 60
syscall syscall