From e512650440205cc1c7d39d1a0f1daf209d853741 Mon Sep 17 00:00:00 2001 From: nub31 Date: Fri, 27 Feb 2026 21:29:28 +0100 Subject: [PATCH] ... --- compiler/TypeChecker.cs | 50 ++++++++++++++++++++++++++------------- examples/build.sh | 9 +++---- examples/core/print.nub | 6 +++++ examples/program/main.nub | 13 +++++++++- 4 files changed, 57 insertions(+), 21 deletions(-) create mode 100644 examples/core/print.nub diff --git a/compiler/TypeChecker.cs b/compiler/TypeChecker.cs index 36b6a4f..df641c2 100644 --- a/compiler/TypeChecker.cs +++ b/compiler/TypeChecker.cs @@ -119,20 +119,9 @@ public class TypeChecker if (statement.Expression is not NodeExpressionFuncCall funcCall) throw BasicError("Expected statement or function call", statement); - var target = CheckExpression(funcCall.Target, null); - if (target.Type is not NubTypeFunc funcType) - throw BasicError("Expected a function type", target); + var expr = CheckExpressionFuncCall(funcCall, null); - if (funcType.Parameters.Count != funcCall.Parameters.Count) - throw BasicError($"Expected {funcType.Parameters.Count} parameters but got {funcCall.Parameters.Count}", funcCall); - - var parameters = new List(); - for (int i = 0; i < funcCall.Parameters.Count; i++) - { - parameters.Add(CheckExpression(funcCall.Parameters[i], funcType.Parameters[i])); - } - - return new TypedNodeStatementFuncCall(statement.Tokens, target, parameters); + return new TypedNodeStatementFuncCall(expr.Tokens, expr.Target, expr.Parameters); } private TypedNodeStatementIf CheckStatementIf(NodeStatementIf statement) @@ -432,6 +421,14 @@ public class TypeChecker return new TypedNodeExpressionMemberAccess(expression.Tokens, field.Type, target, expression.Name); } + case NubTypeAnonymousStruct anonymousStructType: + { + var field = anonymousStructType.Fields.FirstOrDefault(x => x.Name == expression.Name.Ident); + if (field == null) + throw BasicError($"Struct '{target.Type}' does not have a field matching the name '{expression.Name.Ident}'", target); + + return new TypedNodeExpressionMemberAccess(expression.Tokens, field.Type, target, expression.Name); + } case NubTypeEnumVariant enumVariantType: { if (!moduleGraph.TryResolveModule(enumVariantType.EnumType.Module, out var module)) @@ -466,7 +463,11 @@ public class TypeChecker var parameters = new List(); for (int i = 0; i < expression.Parameters.Count; i++) { - parameters.Add(CheckExpression(expression.Parameters[i], funcType.Parameters[i])); + var parameter = CheckExpression(expression.Parameters[i], funcType.Parameters[i]); + if (!parameter.Type.IsAssignableTo(funcType.Parameters[i])) + throw BasicError($"Parameter {i + 1} does is not assignable to '{funcType.Parameters[i]}'", parameter); + + parameters.Add(parameter); } return new TypedNodeExpressionFuncCall(expression.Tokens, funcType.ReturnType, target, parameters); @@ -484,7 +485,7 @@ public class TypeChecker var type = ResolveType(expression.Type); if (type is not NubTypeStruct structType) throw BasicError("Type of struct literal is not a struct", expression); - + if (!moduleGraph.TryResolveType(structType.Module, structType.Name, structType.Module == currentModule, out var info)) throw BasicError($"Type '{structType}' struct literal not found", expression); @@ -531,7 +532,24 @@ public class TypeChecker return new TypedNodeExpressionStructLiteral(expression.Tokens, structType, initializers); } - // todo(nub31): Infer anonymous struct types if expectedType is anonymous struct + else if (expectedType is NubTypeAnonymousStruct anonymousStructType) + { + var initializers = new List(); + foreach (var initializer in expression.Initializers) + { + var field = anonymousStructType.Fields.FirstOrDefault(x => x.Name == initializer.Name.Ident); + if (field == null) + throw BasicError($"Field '{initializer.Name.Ident}' does not exist on anonymous struct '{anonymousStructType}'", initializer.Name); + + var value = CheckExpression(initializer.Value, field.Type); + if (!value.Type.IsAssignableTo(field.Type)) + throw BasicError($"Type of assignment ({value.Type}) does not match expected type of field '{field.Name}' ({field.Type})", initializer.Name); + + initializers.Add(new TypedNodeExpressionStructLiteral.Initializer(initializer.Tokens, initializer.Name, value)); + } + + return new TypedNodeExpressionStructLiteral(expression.Tokens, anonymousStructType, initializers); + } else { var initializers = new List(); diff --git a/examples/build.sh b/examples/build.sh index 66910db..fe2668e 100755 --- a/examples/build.sh +++ b/examples/build.sh @@ -1,12 +1,13 @@ set -e +pushd core +dotnet run --project ../../compiler print.nub --type=lib +popd + pushd math dotnet run --project ../../compiler math.nub --type=lib -# pushd .build -# unzip out.nublib -# popd popd pushd program -dotnet run --project ../../compiler main.nub ../math/.build/out.nublib +dotnet run --project ../../compiler main.nub ../math/.build/out.nublib ../core/.build/out.nublib popd \ No newline at end of file diff --git a/examples/core/print.nub b/examples/core/print.nub new file mode 100644 index 0000000..abefd4c --- /dev/null +++ b/examples/core/print.nub @@ -0,0 +1,6 @@ +module print + +extern func puts(^u8 text) + +export func print(text: string) { +} \ No newline at end of file diff --git a/examples/program/main.nub b/examples/program/main.nub index 4693c99..d3a308d 100644 --- a/examples/program/main.nub +++ b/examples/program/main.nub @@ -1,6 +1,17 @@ module main +struct Pos { + x: i32 + y: i32 +} + func main(): i32 { - return math::add(1 2) + test({ x = 23 y = 23 }) + + return 1 +} + +func test(x: Pos): void +{ } \ No newline at end of file