...
This commit is contained in:
@@ -379,7 +379,7 @@ public class QBEGenerator
|
||||
_labelIndex = 0;
|
||||
_tmpIndex = 0;
|
||||
|
||||
_writer.Write("export function ");
|
||||
_writer.Write(funcDef.ExternSymbol != null ? "export function " : "function ");
|
||||
|
||||
if (funcDef.Signature.ReturnType is not VoidTypeNode)
|
||||
{
|
||||
|
||||
@@ -6,7 +6,7 @@ public record FuncParameterNode(string Name, TypeNode Type) : 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;
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Diagnostics;
|
||||
using NubLang.Diagnostics;
|
||||
using NubLang.Parsing.Syntax;
|
||||
using NubLang.Tokenization;
|
||||
@@ -59,7 +60,11 @@ public sealed class TypeChecker
|
||||
|
||||
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)
|
||||
@@ -124,7 +129,7 @@ public sealed class TypeChecker
|
||||
_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)
|
||||
@@ -308,7 +313,7 @@ public sealed class TypeChecker
|
||||
var parameterExpression = CheckExpression(parameter, 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);
|
||||
@@ -402,12 +407,77 @@ public sealed class TypeChecker
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
@@ -453,7 +523,7 @@ public sealed class TypeChecker
|
||||
{
|
||||
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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -3,8 +3,8 @@ NUBC = ../compiler/NubLang.CLI/bin/Debug/net9.0/nubc
|
||||
out: .build/out.o
|
||||
gcc -nostartfiles -o out x86_64.s .build/out.o
|
||||
|
||||
.build/out.o: $(NUBC) main.nub
|
||||
$(NUBC) main.nub
|
||||
.build/out.o: $(NUBC) src/main.nub src/test.nub
|
||||
$(NUBC) src/main.nub src/test.nub
|
||||
|
||||
.PHONY: $(NUBC)
|
||||
$(NUBC):
|
||||
|
||||
14
example/src/main.nub
Normal file
14
example/src/main.nub
Normal 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
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
.globl _start
|
||||
_start:
|
||||
mov rdi, rsp
|
||||
call main.main
|
||||
call main
|
||||
mov rdi, rax
|
||||
mov rax, 60
|
||||
syscall
|
||||
|
||||
Reference in New Issue
Block a user