From 0afb18e4a6d0b8c679f78b8acda6ce905a8a888e Mon Sep 17 00:00:00 2001 From: nub31 Date: Sun, 6 Jul 2025 00:15:35 +0200 Subject: [PATCH] ... --- src/compiler/Generation/QBE/QBEGenerator.cs | 179 +++++++-------- src/compiler/Syntax/Binding/Binder.cs | 232 ++++++++++++-------- src/compiler/Syntax/DefinitionTable.cs | 23 +- src/compiler/Syntax/Node/Definition.cs | 23 +- src/compiler/Syntax/Node/Expression.cs | 38 ++-- src/compiler/Syntax/Node/Statement.cs | 2 +- src/compiler/Syntax/NubBoundType.cs | 191 ++++++++++++++++ src/compiler/Syntax/NubType.cs | 12 - src/compiler/Syntax/Parsing/Parser.cs | 15 +- 9 files changed, 480 insertions(+), 235 deletions(-) create mode 100644 src/compiler/Syntax/NubBoundType.cs diff --git a/src/compiler/Generation/QBE/QBEGenerator.cs b/src/compiler/Generation/QBE/QBEGenerator.cs index d0a07ef..a0f5b72 100644 --- a/src/compiler/Generation/QBE/QBEGenerator.cs +++ b/src/compiler/Generation/QBE/QBEGenerator.cs @@ -132,20 +132,25 @@ public static class QBEGenerator return $"$impl{++_implFuncNameIndex}"; } - private static string CustomTypeName(NubCustomType customType) + private static string StructTypeName(BoundNubStructType structType) { - return $":{customType.Namespace}_{customType.Name}"; + return $":{structType.Namespace}_{structType.Name}"; } - private static void EmitStore(NubType type, string value, string destination) + private static string TraitTypeName(BoundNubTraitType traitType) + { + return $":{traitType.Namespace}_{traitType.Name}"; + } + + private static void EmitStore(BoundNubType type, string value, string destination) { var store = type switch { - NubComplexType => "storel", - NubSimpleType simpleType => simpleType switch + BoundNubComplexType => "storel", + BoundNubSimpleType simpleType => simpleType switch { - NubFuncType or NubPointerType => "loadl", - NubPrimitiveType primitiveType => primitiveType.Kind switch + BoundNubFuncType or BoundNubPointerType => "loadl", + BoundNubPrimitiveType primitiveType => primitiveType.Kind switch { PrimitiveTypeKind.I64 or PrimitiveTypeKind.U64 => "storel", PrimitiveTypeKind.I32 or PrimitiveTypeKind.U32 => "storew", @@ -163,16 +168,16 @@ public static class QBEGenerator _writer.Indented($"{store} {value}, {destination}"); } - private static Val EmitLoad(NubType type, string from) + private static Val EmitLoad(BoundNubType type, string from) { var into = TmpName(); var load = type switch { - NubComplexType => "loadl", - NubSimpleType simpleType => simpleType switch + BoundNubComplexType => "loadl", + BoundNubSimpleType simpleType => simpleType switch { - NubFuncType or NubPointerType => "loadl", - NubPrimitiveType primitiveType => primitiveType.Kind switch + BoundNubFuncType or BoundNubPointerType => "loadl", + BoundNubPrimitiveType primitiveType => primitiveType.Kind switch { PrimitiveTypeKind.I64 or PrimitiveTypeKind.U64 => "loadl", PrimitiveTypeKind.I32 or PrimitiveTypeKind.U32 => "loadw", @@ -199,7 +204,7 @@ public static class QBEGenerator _writer.Indented($"call $nub_memcpy(l {source}, l {destination}, l {length})"); } - private static string EmitArraySizeInBytes(NubArrayType type, string array) + private static string EmitArraySizeInBytes(BoundNubArrayType type, string array) { var size = TmpName(); _writer.Indented($"{size} =l loadl {array}"); @@ -263,22 +268,23 @@ public static class QBEGenerator switch (source.Type) { - case NubComplexType complexType: + case BoundNubComplexType complexType: { var size = complexType switch { - NubArrayType arrayType => EmitArraySizeInBytes(arrayType, value), - NubCStringType => EmitCStringSizeInBytes(value), - NubStringType => EmitStringSizeInBytes(value), - NubCustomType customType => SizeOf(customType).ToString(), + BoundNubArrayType arrayType => EmitArraySizeInBytes(arrayType, value), + BoundNubCStringType => EmitCStringSizeInBytes(value), + BoundNubStringType => EmitStringSizeInBytes(value), + BoundNubStructType structType => SizeOf(structType).ToString(), + BoundNubTraitType traitType => SizeOf(traitType).ToString(), _ => throw new ArgumentOutOfRangeException(nameof(complexType)) }; switch (complexType) { - case NubArrayType: - case NubCStringType: - case NubStringType: + case BoundNubArrayType: + case BoundNubCStringType: + case BoundNubStringType: { var buffer = TmpName(); _writer.Indented($"{buffer} =l alloc8 {size}"); @@ -286,7 +292,8 @@ public static class QBEGenerator EmitStore(source.Type, buffer, destinationPointer); return; } - case NubCustomType: + case BoundNubStructType: + case BoundNubTraitType: { EmitMemcpy(value, destinationPointer, size); return; @@ -297,7 +304,7 @@ public static class QBEGenerator } } } - case NubSimpleType simpleType: + case BoundNubSimpleType simpleType: { EmitStore(simpleType, value, destinationPointer); return; @@ -338,16 +345,17 @@ public static class QBEGenerator switch (source.Type) { - case NubComplexType complexType: + case BoundNubComplexType complexType: { var destination = TmpName(); var size = complexType switch { - NubArrayType arrayType => EmitArraySizeInBytes(arrayType, value), - NubCStringType => EmitCStringSizeInBytes(value), - NubStringType => EmitStringSizeInBytes(value), - NubCustomType customType => SizeOf(customType).ToString(), + BoundNubArrayType arrayType => EmitArraySizeInBytes(arrayType, value), + BoundNubCStringType => EmitCStringSizeInBytes(value), + BoundNubStringType => EmitStringSizeInBytes(value), + BoundNubStructType structType => SizeOf(structType).ToString(), + BoundNubTraitType traitType => SizeOf(traitType).ToString(), _ => throw new ArgumentOutOfRangeException(nameof(complexType)) }; @@ -355,7 +363,7 @@ public static class QBEGenerator EmitMemcpy(value, destination, size); return destination; } - case NubSimpleType: + case BoundNubSimpleType: { return value; } @@ -366,15 +374,15 @@ public static class QBEGenerator } } - private static string QBEAssign(NubType type) + private static string QBEAssign(BoundNubType type) { return type switch { - NubComplexType => "=l", - NubSimpleType simpleType => simpleType switch + BoundNubComplexType => "=l", + BoundNubSimpleType simpleType => simpleType switch { - NubFuncType or NubFuncType => "=l", - NubPrimitiveType primitiveType => primitiveType.Kind switch + BoundNubFuncType or BoundNubFuncType => "=l", + BoundNubPrimitiveType primitiveType => primitiveType.Kind switch { PrimitiveTypeKind.I64 or PrimitiveTypeKind.U64 => "=l", PrimitiveTypeKind.I32 or PrimitiveTypeKind.U32 => "=w", @@ -390,11 +398,11 @@ public static class QBEGenerator }; } - private static int AlignmentOf(NubType type) + private static int AlignmentOf(BoundNubType type) { switch (type) { - case NubPrimitiveType primitiveType: + case BoundNubPrimitiveType primitiveType: { return primitiveType.Kind switch { @@ -405,17 +413,17 @@ public static class QBEGenerator _ => throw new ArgumentOutOfRangeException() }; } - case NubStructType structType: + case BoundNubStructType structType: { var structDef = _definitionTable.LookupStruct(structType.Namespace, structType.Name); return structDef.Fields.Max(f => AlignmentOf(f.Type)); } - case NubTraitType: - case NubPointerType: - case NubArrayType: - case NubCStringType: - case NubStringType: - case NubFuncType: + case BoundNubTraitType: + case BoundNubPointerType: + case BoundNubArrayType: + case BoundNubCStringType: + case BoundNubStringType: + case BoundNubFuncType: return 8; default: throw new ArgumentOutOfRangeException(); @@ -427,11 +435,11 @@ public static class QBEGenerator return (offset + alignment - 1) & ~(alignment - 1); } - private static int SizeOf(NubType type) + private static int SizeOf(BoundNubType type) { switch (type) { - case NubPrimitiveType primitiveType: + case BoundNubPrimitiveType primitiveType: { return primitiveType.Kind switch { @@ -442,7 +450,7 @@ public static class QBEGenerator _ => throw new ArgumentOutOfRangeException() }; } - case NubStructType structType: + case BoundNubStructType structType: { var structDef = _definitionTable.LookupStruct(structType.Namespace, structType.Name); var size = 0; @@ -461,13 +469,13 @@ public static class QBEGenerator return size; } - case NubTraitType: + case BoundNubTraitType: return 16; - case NubPointerType: - case NubArrayType: - case NubCStringType: - case NubStringType: - case NubFuncType: + case BoundNubPointerType: + case BoundNubArrayType: + case BoundNubCStringType: + case BoundNubStringType: + case BoundNubFuncType: return 8; default: throw new ArgumentOutOfRangeException(); @@ -494,16 +502,17 @@ public static class QBEGenerator throw new UnreachableException($"Member '{member}' not found in struct"); } - private static string FuncQBETypeName(NubType type) + private static string FuncQBETypeName(BoundNubType type) { return type switch { - NubCustomType customType => CustomTypeName(customType), - NubComplexType => "l", - NubSimpleType simpleType => simpleType switch + BoundNubStructType structType => StructTypeName(structType), + BoundNubTraitType traitType => TraitTypeName(traitType), + BoundNubComplexType => "l", + BoundNubSimpleType simpleType => simpleType switch { - NubPointerType or NubFuncType => "l", - NubPrimitiveType primitiveType => primitiveType.Kind switch + BoundNubPointerType or BoundNubFuncType => "l", + BoundNubPrimitiveType primitiveType => primitiveType.Kind switch { PrimitiveTypeKind.I64 or PrimitiveTypeKind.U64 => "l", PrimitiveTypeKind.I32 or PrimitiveTypeKind.U32 => "w", @@ -521,7 +530,7 @@ public static class QBEGenerator }; } - private static void EmitFuncDefinition(BoundNode debugNode, string name, List parameters, NubType returnType, BoundBlock body, bool exported) + private static void EmitFuncDefinition(BoundNode debugNode, string name, List parameters, BoundNubType returnType, BoundBlock body, bool exported) { _variables.Clear(); _variableScopes.Clear(); @@ -536,7 +545,7 @@ public static class QBEGenerator } builder.Append("function "); - if (returnType is not NubVoidType) + if (returnType is not BoundNubVoidType) { builder.Append(FuncQBETypeName(returnType) + ' '); } @@ -556,7 +565,7 @@ public static class QBEGenerator if (body.Statements.LastOrDefault() is not BoundReturnNode) { - if (returnType is NubVoidType) + if (returnType is BoundNubVoidType) { _writer.Indented("ret"); } @@ -567,7 +576,7 @@ public static class QBEGenerator // private static void EmitStructDefinition(BoundStructNode structDef) // { - // var structType = new NubCustomType(structDef.Namespace, structDef.Name); + // var structType = new BoundNubCustomType(structDef.Namespace, structDef.Name); // _writer.WriteLine($"type {CustomTypeName(structType)} = {{ "); // // var types = new Dictionary(); @@ -591,12 +600,12 @@ public static class QBEGenerator // { // return field.Type switch // { - // NubCustomType customType => CustomTypeName(customType), - // NubComplexType => "l", - // NubSimpleType simpleType => simpleType switch + // BoundNubCustomType customType => CustomTypeName(customType), + // BoundNubComplexType => "l", + // BoundNubSimpleType simpleType => simpleType switch // { - // NubPointerType or NubFuncType => "l", - // NubPrimitiveType primitiveType => primitiveType.Kind switch + // BoundNubPointerType or BoundNubFuncType => "l", + // BoundNubPrimitiveType primitiveType => primitiveType.Kind switch // { // PrimitiveTypeKind.I64 or PrimitiveTypeKind.U64 => "l", // PrimitiveTypeKind.I32 or PrimitiveTypeKind.U32 => "w", @@ -615,7 +624,7 @@ public static class QBEGenerator // // private static void EmitTraitVTable(BoundTraitNode traitDef) // { - // _writer.WriteLine($"type {CustomTypeName(new NubCustomType(traitDef.Namespace, traitDef.Name))} = {{"); + // _writer.WriteLine($"type {CustomTypeName(new BoundNubCustomType(traitDef.Namespace, traitDef.Name))} = {{"); // // foreach (var func in traitDef.Functions) // { @@ -810,10 +819,10 @@ public static class QBEGenerator private static Val EmitArrayIndexAccess(BoundArrayIndexAccessNode arrayIndexAccess) { - var array = EmitUnwrap(EmitExpression(arrayIndexAccess.Array)); + var array = EmitUnwrap(EmitExpression(arrayIndexAccess.Target)); var index = EmitUnwrap(EmitExpression(arrayIndexAccess.Index)); - var elementType = ((NubArrayType)arrayIndexAccess.Array.Type).ElementType; + var elementType = ((BoundNubArrayType)arrayIndexAccess.Target.Type).ElementType; var pointer = TmpName(); _writer.Indented($"{pointer} =l mul {index}, {SizeOf(elementType)}"); @@ -892,7 +901,7 @@ public static class QBEGenerator return new Val(outputName, binaryExpression.Type, ValKind.Direct); } - private static string EmitBinaryInstructionFor(BinaryExpressionOperator op, NubType type, string left, string right) + private static string EmitBinaryInstructionFor(BinaryExpressionOperator op, BoundNubType type, string left, string right) { if (op is BinaryExpressionOperator.Equal or @@ -1097,17 +1106,12 @@ public static class QBEGenerator private static Val EmitStructInitializer(BoundStructInitializerNode structInitializer, string? destination = null) { - if (structInitializer.StructType is not NubCustomType structType) - { - throw new UnreachableException(); - } - - var @struct = _definitionTable.LookupStruct(structType.Namespace, structType.Name); + var @struct = _definitionTable.LookupStruct(structInitializer.StructType.Namespace, structInitializer.StructType.Name); if (destination == null) { destination = TmpName(); - var size = SizeOf(structType); + var size = SizeOf(structInitializer.StructType); _writer.Indented($"{destination} =l alloc8 {size}"); } @@ -1125,7 +1129,7 @@ public static class QBEGenerator EmitCopyIntoOrInitialize(valueExpression, offset); } - return new Val(destination, structType, ValKind.Direct); + return new Val(destination, structInitializer.StructType, ValKind.Direct); } private static Val EmitUnaryExpression(BoundUnaryExpressionNode unaryExpression) @@ -1139,16 +1143,16 @@ public static class QBEGenerator { switch (unaryExpression.Operand.Type) { - case NubPrimitiveType { Kind: PrimitiveTypeKind.I64 }: + case BoundNubPrimitiveType { Kind: PrimitiveTypeKind.I64 }: _writer.Indented($"{outputName} =l neg {operand}"); return new Val(outputName, unaryExpression.Type, ValKind.Direct); - case NubPrimitiveType { Kind: PrimitiveTypeKind.I32 or PrimitiveTypeKind.I16 or PrimitiveTypeKind.I8 }: + case BoundNubPrimitiveType { Kind: PrimitiveTypeKind.I32 or PrimitiveTypeKind.I16 or PrimitiveTypeKind.I8 }: _writer.Indented($"{outputName} =w neg {operand}"); return new Val(outputName, unaryExpression.Type, ValKind.Direct); - case NubPrimitiveType { Kind: PrimitiveTypeKind.F64 }: + case BoundNubPrimitiveType { Kind: PrimitiveTypeKind.F64 }: _writer.Indented($"{outputName} =d neg {operand}"); return new Val(outputName, unaryExpression.Type, ValKind.Direct); - case NubPrimitiveType { Kind: PrimitiveTypeKind.F32 }: + case BoundNubPrimitiveType { Kind: PrimitiveTypeKind.F32 }: _writer.Indented($"{outputName} =s neg {operand}"); return new Val(outputName, unaryExpression.Type, ValKind.Direct); } @@ -1159,7 +1163,7 @@ public static class QBEGenerator { switch (unaryExpression.Operand.Type) { - case NubPrimitiveType { Kind: PrimitiveTypeKind.Bool }: + case BoundNubPrimitiveType { Kind: PrimitiveTypeKind.Bool }: _writer.Indented($"{outputName} =w xor {operand}, 1"); return new Val(outputName, unaryExpression.Type, ValKind.Direct); } @@ -1186,7 +1190,7 @@ public static class QBEGenerator _writer.Indented($"{output} =l add {target}, {offset}"); // If the accessed member is an inline struct, it will not be a pointer - if (structFieldAccess.Type is NubStructType) + if (structFieldAccess.Type is BoundNubStructType) { return new Val(output, structFieldAccess.Type, ValKind.Direct); } @@ -1203,8 +1207,7 @@ public static class QBEGenerator { var target = EmitExpression(traitImplFuncAccess.Target); - var impl = _definitionTable.LookupTraitImpl(traitImplFuncAccess.Target.Type); - var funcImpl = _definitionTable.LookupTraitFuncImpl(impl, traitImplFuncAccess.FuncName); + var funcImpl = _definitionTable.LookupTraitFuncImpl(traitImplFuncAccess.Target.Type, traitImplFuncAccess.FuncName); var name = ImplFuncName(); _implFunctions.TryAdd(funcImpl, name); @@ -1272,7 +1275,7 @@ internal class Variable(string name, Val val) public Val Val { get; } = val; } -internal record Val(string Name, NubType Type, ValKind Kind, MethodCallContext? FuncCallContext = null); +internal record Val(string Name, BoundNubType Type, ValKind Kind, MethodCallContext? FuncCallContext = null); internal record MethodCallContext(Val ThisArg); diff --git a/src/compiler/Syntax/Binding/Binder.cs b/src/compiler/Syntax/Binding/Binder.cs index 0f039dd..c1dde60 100644 --- a/src/compiler/Syntax/Binding/Binder.cs +++ b/src/compiler/Syntax/Binding/Binder.cs @@ -14,8 +14,8 @@ public sealed class Binder private readonly DefinitionTable _definitionTable; // TODO: Implement proper variable tracking and scoping - private Dictionary _variables = new(); - private NubType? _functionReturnType; + private Dictionary _variables = new(); + private BoundNubType? _functionReturnType; public Binder(SyntaxTree syntaxTree, DefinitionTable definitionTable) { @@ -66,24 +66,34 @@ public sealed class Binder foreach (var function in node.Functions) { + var parameters = new List(); + foreach (var parameter in function.Parameters) { - _variables[parameter.Name] = parameter.Type; + _variables[parameter.Name] = BindType(parameter.Type); + parameters.Add(new BoundFuncParameterNode(parameter.Tokens, parameter.Name, BindType(parameter.Type))); } - functions.Add(new BoundTraitFuncImplNode(function.Tokens, function.Name, function.Parameters, BindType(function.ReturnType), BindBlock(function.Body))); + functions.Add(new BoundTraitFuncImplNode(function.Tokens, function.Name, parameters, BindType(function.ReturnType), BindBlock(function.Body))); } - return new BoundTraitImplNode(node.Tokens, node.Namespace, node.TraitType, node.ForType, functions); + return new BoundTraitImplNode(node.Tokens, node.Namespace, BindType(node.TraitType), BindType(node.ForType), functions); } private BoundTraitNode BindTraitDefinition(TraitNode node) { var functions = new List(); - foreach (var func in node.Functions) + foreach (var function in node.Functions) { - functions.Add(new BoundTraitFuncNode(node.Tokens, func.Name, func.Parameters, BindType(func.ReturnType))); + var parameters = new List(); + + foreach (var parameter in function.Parameters) + { + parameters.Add(new BoundFuncParameterNode(parameter.Tokens, parameter.Name, BindType(parameter.Type))); + } + + functions.Add(new BoundTraitFuncNode(node.Tokens, function.Name, parameters, BindType(function.ReturnType))); } return new BoundTraitNode(node.Tokens, node.Namespace, node.Name, functions); @@ -99,10 +109,10 @@ public sealed class Binder if (field.Value.HasValue) { - value = BindExpression(field.Value.Value, field.Type); + value = BindExpression(field.Value.Value, BindType(field.Type)); } - structFields.Add(new BoundStructFieldNode(field.Tokens, field.Index, field.Name, field.Type, value)); + structFields.Add(new BoundStructFieldNode(field.Tokens, field.Index, field.Name, BindType(field.Type), value)); } return new BoundStructNode(node.Tokens, node.Namespace, node.Name, structFields); @@ -110,7 +120,14 @@ public sealed class Binder private BoundExternFuncNode BindExternFuncDefinition(ExternFuncNode node) { - return new BoundExternFuncNode(node.Tokens, node.Namespace, node.Name, node.CallName, node.Parameters, BindType(node.ReturnType)); + var parameters = new List(); + + foreach (var parameter in node.Parameters) + { + parameters.Add(new BoundFuncParameterNode(parameter.Tokens, parameter.Name, BindType(parameter.Type))); + } + + return new BoundExternFuncNode(node.Tokens, node.Namespace, node.Name, node.CallName, parameters, BindType(node.ReturnType)); } private BoundLocalFuncNode BindLocalFuncDefinition(LocalFuncNode node) @@ -118,14 +135,17 @@ public sealed class Binder _variables.Clear(); _functionReturnType = BindType(node.ReturnType); + var parameters = new List(); + foreach (var parameter in node.Parameters) { - _variables[parameter.Name] = parameter.Type; + _variables[parameter.Name] = BindType(parameter.Type); + parameters.Add(new BoundFuncParameterNode(parameter.Tokens, parameter.Name, BindType(parameter.Type))); } var body = BindBlock(node.Body); - return new BoundLocalFuncNode(node.Tokens, node.Namespace, node.Name, node.Parameters, body, BindType(node.ReturnType), node.Exported); + return new BoundLocalFuncNode(node.Tokens, node.Namespace, node.Name, parameters, body, BindType(node.ReturnType), node.Exported); } private BoundBlock BindBlock(BlockNode node) @@ -186,7 +206,7 @@ public sealed class Binder ); } - return new BoundIfNode(statement.Tokens, BindExpression(statement.Condition, NubPrimitiveType.Bool), BindBlock(statement.Body), elseStatement); + return new BoundIfNode(statement.Tokens, BindExpression(statement.Condition, BoundNubPrimitiveType.Bool), BindBlock(statement.Body), elseStatement); } private BoundReturnNode BindReturn(ReturnNode statement) @@ -208,11 +228,11 @@ public sealed class Binder private BoundVariableDeclarationNode BindVariableDeclaration(VariableDeclarationNode statement) { - NubType? type = null; + BoundNubType? type = null; if (statement.ExplicitType.HasValue) { - type = statement.ExplicitType.Value; + type = BindType(statement.ExplicitType.Value); } var assignment = Optional.Empty(); @@ -230,15 +250,15 @@ public sealed class Binder _variables[statement.Name] = type; - return new BoundVariableDeclarationNode(statement.Tokens, statement.Name, statement.ExplicitType, assignment, type); + return new BoundVariableDeclarationNode(statement.Tokens, statement.Name, assignment, type); } private BoundWhileNode BindWhile(WhileNode statement) { - return new BoundWhileNode(statement.Tokens, BindExpression(statement.Condition, NubPrimitiveType.Bool), BindBlock(statement.Body)); + return new BoundWhileNode(statement.Tokens, BindExpression(statement.Condition, BoundNubPrimitiveType.Bool), BindBlock(statement.Body)); } - private BoundExpressionNode BindExpression(ExpressionNode node, NubType? expectedType = null) + private BoundExpressionNode BindExpression(ExpressionNode node, BoundNubType? expectedType = null) { return node switch { @@ -261,28 +281,33 @@ public sealed class Binder private BoundAddressOfNode BindAddressOf(AddressOfNode expression) { var inner = BindExpression(expression.Expression); - return new BoundAddressOfNode(expression.Tokens, new NubPointerType(inner.Type), inner); + return new BoundAddressOfNode(expression.Tokens, new BoundNubPointerType(inner.Type), inner); } private BoundAnonymousFuncNode BindAnonymousFunc(AnonymousFuncNode expression) { - var parameterTypes = expression.Parameters.Select(x => x.Type).ToList(); + var parameters = new List(); + + foreach (var parameter in expression.Parameters) + { + parameters.Add(new BoundFuncParameterNode(parameter.Tokens, parameter.Name, BindType(parameter.Type))); + } var body = BindBlock(expression.Body); - return new BoundAnonymousFuncNode(expression.Tokens, new NubFuncType(BindType(expression.ReturnType), parameterTypes), expression.Parameters, body, BindType(expression.ReturnType)); + return new BoundAnonymousFuncNode(expression.Tokens, new BoundNubFuncType(BindType(expression.ReturnType), parameters.Select(x => x.Type).ToList()), parameters, body, BindType(expression.ReturnType)); } private BoundArrayIndexAccessNode BindArrayIndexAccess(ArrayIndexAccessNode expression) { - var boundArray = BindExpression(expression.Array); - var elementType = ((NubArrayType)boundArray.Type).ElementType; - return new BoundArrayIndexAccessNode(expression.Tokens, elementType, boundArray, BindExpression(expression.Index, NubPrimitiveType.U64)); + var boundArray = BindExpression(expression.Target); + var elementType = ((BoundNubArrayType)boundArray.Type).ElementType; + return new BoundArrayIndexAccessNode(expression.Tokens, elementType, boundArray, BindExpression(expression.Index, BoundNubPrimitiveType.U64)); } private BoundArrayInitializerNode BindArrayInitializer(ArrayInitializerNode expression) { - return new BoundArrayInitializerNode(expression.Tokens, new NubArrayType(expression.ElementType), BindExpression(expression.Capacity, NubPrimitiveType.U64), expression.ElementType); + return new BoundArrayInitializerNode(expression.Tokens, new BoundNubArrayType(BindType(expression.ElementType)), BindExpression(expression.Capacity, BoundNubPrimitiveType.U64), BindType(expression.ElementType)); } private BoundBinaryExpressionNode BindBinaryExpression(BinaryExpressionNode expression) @@ -295,7 +320,7 @@ public sealed class Binder private BoundDereferenceNode BindDereference(DereferenceNode expression) { var boundExpression = BindExpression(expression.Expression); - var dereferencedType = ((NubPointerType)boundExpression.Type).BaseType; + var dereferencedType = ((BoundNubPointerType)boundExpression.Type).BaseType; return new BoundDereferenceNode(expression.Tokens, dereferencedType, boundExpression); } @@ -303,8 +328,7 @@ public sealed class Binder { var boundExpression = BindExpression(expression.Expression); - var funcType = (NubFuncType)boundExpression.Type; - var returnType = BindType(funcType.ReturnType); + var funcType = (BoundNubFuncType)boundExpression.Type; var parameters = new List(); @@ -320,7 +344,7 @@ public sealed class Binder parameters.Add(BindExpression(parameter, expectedType)); } - return new BoundFuncCallNode(expression.Tokens, returnType, boundExpression, parameters); + return new BoundFuncCallNode(expression.Tokens, funcType.ReturnType, boundExpression, parameters); } private BoundExpressionNode BindIdentifier(IdentifierNode expression) @@ -336,8 +360,8 @@ public sealed class Binder var localFunc = localFuncs[0]; - var type = new NubFuncType(BindType(localFunc.ReturnType), localFunc.Parameters.Select(p => p.Type).ToList()); - return new BoundLocalFuncIdentNode(expression.Tokens, type, @namespace, expression.Name); + var type = new NubFuncType(localFunc.ReturnType, localFunc.Parameters.Select(p => p.Type).ToList()); + return new BoundLocalFuncIdentNode(expression.Tokens, BindType(type), @namespace, expression.Name); } var externFuncs = _definitionTable.LookupExternFunc(@namespace, expression.Name).ToArray(); @@ -350,8 +374,8 @@ public sealed class Binder var externFunc = externFuncs[0]; - var type = new NubFuncType(BindType(externFunc.ReturnType), externFunc.Parameters.Select(p => p.Type).ToList()); - return new BoundExternFuncIdentNode(expression.Tokens, type, @namespace, expression.Name); + var type = new NubFuncType(externFunc.ReturnType, externFunc.Parameters.Select(p => p.Type).ToList()); + return new BoundExternFuncIdentNode(expression.Tokens, BindType(type), @namespace, expression.Name); } if (!expression.Namespace.HasValue) @@ -362,14 +386,14 @@ public sealed class Binder throw new BindException(Diagnostic.Error($"No identifier with then name {(expression.Namespace.HasValue ? $"{expression.Namespace.Value}::" : "")}{expression.Name} exists").Build()); } - private BoundLiteralNode BindLiteral(LiteralNode expression, NubType? expectedType = null) + private BoundLiteralNode BindLiteral(LiteralNode expression, BoundNubType? expectedType = null) { var type = expectedType ?? expression.Kind switch { - LiteralKind.Integer => NubPrimitiveType.I64, - LiteralKind.Float => NubPrimitiveType.F64, - LiteralKind.String => new NubStringType(), - LiteralKind.Bool => NubPrimitiveType.Bool, + LiteralKind.Integer => BoundNubPrimitiveType.I64, + LiteralKind.Float => BoundNubPrimitiveType.F64, + LiteralKind.String => new BoundNubStringType(), + LiteralKind.Bool => BoundNubPrimitiveType.Bool, _ => throw new ArgumentOutOfRangeException() }; @@ -380,8 +404,7 @@ public sealed class Binder { var boundExpression = BindExpression(expression.Target); - var traitFuncImpls = _definitionTable.LookupTraitImpl(boundExpression.Type).SelectMany(x => _definitionTable.LookupTraitFuncImpl(x, expression.Member)).ToArray(); - + var traitFuncImpls = _definitionTable.LookupTraitFuncImpl(UnbindType(boundExpression.Type), expression.Member).ToArray(); if (traitFuncImpls.Length > 0) { if (traitFuncImpls.Length > 1) @@ -391,18 +414,18 @@ public sealed class Binder var impl = traitFuncImpls[0]; - var type = new NubFuncType(BindType(impl.ReturnType), impl.Parameters.Select(p => BindType(p.Type)).ToList()); + var type = new BoundNubFuncType(BindType(impl.ReturnType), impl.Parameters.Select(p => BindType(p.Type)).ToList()); return new BoundTraitImplFuncAccessNode(expression.Tokens, type, boundExpression, expression.Member); } - if (boundExpression.Type is NubCustomType customType) + if (boundExpression.Type is BoundNubTraitType traitType) { - var traits = _definitionTable.LookupTrait(customType.Namespace, customType.Name).ToArray(); + var traits = _definitionTable.LookupTrait(traitType.Namespace, traitType.Name).ToArray(); if (traits.Length > 0) { if (traits.Length > 1) { - throw new BindException(Diagnostic.Error($"Trait {customType.Namespace}::{customType.Name} has multiple definitions").Build()); + throw new BindException(Diagnostic.Error($"Trait {traitType.Namespace}::{traitType.Name} has multiple definitions").Build()); } var trait = traits[0]; @@ -417,22 +440,25 @@ public sealed class Binder var traitFunc = traitFuncs[0]; - var type = new NubFuncType(BindType(traitFunc.ReturnType), traitFunc.Parameters.Select(p => BindType(p.Type)).ToList()); - return new BoundTraitFuncAccessNode(expression.Tokens, type, new NubTraitType(trait.Namespace, trait.Name), boundExpression, expression.Member); + var type = new BoundNubFuncType(BindType(traitFunc.ReturnType), traitFunc.Parameters.Select(p => BindType(p.Type)).ToList()); + return new BoundTraitFuncAccessNode(expression.Tokens, type, traitType, boundExpression, expression.Member); } } + } - var structs = _definitionTable.LookupStruct(customType.Namespace, customType.Name).ToArray(); + if (boundExpression.Type is BoundNubStructType structType) + { + var structs = _definitionTable.LookupStruct(structType.Namespace, structType.Name).ToArray(); if (structs.Length > 0) { if (structs.Length > 1) { - throw new BindException(Diagnostic.Error($"Struct {customType.Namespace}::{customType.Name} has multiple definitions").Build()); + throw new BindException(Diagnostic.Error($"Struct {structType.Namespace}::{structType.Name} has multiple definitions").Build()); } var @struct = structs[0]; - var fields = _definitionTable.LookupStructField(@struct, customType.Name).ToArray(); + var fields = _definitionTable.LookupStructField(@struct, expression.Member).ToArray(); if (fields.Length > 0) { if (fields.Length > 1) @@ -442,12 +468,12 @@ public sealed class Binder var field = fields[0]; - return new BoundStructFieldAccessNode(expression.Tokens, field.Type, new NubStructType(@struct.Namespace, @struct.Name), boundExpression, expression.Member); + return new BoundStructFieldAccessNode(expression.Tokens, BindType(field.Type), structType, boundExpression, expression.Member); } } } - throw new BindException(Diagnostic.Error($"{boundExpression.Type} has not member with the name {expression.Member}").Build()); + throw new BindException(Diagnostic.Error($"{boundExpression.Type} does not have a member with the name {expression.Member}").Build()); } private BoundStructInitializerNode BindStructInitializer(StructInitializerNode expression) @@ -487,23 +513,23 @@ public sealed class Binder throw new BindException(Diagnostic.Error($"Struct {@struct.Namespace}::{@struct.Name} has multiple fields with the name {field}").Build()); } - initializers[field] = BindExpression(initializer, fields[0].Type); + initializers[field] = BindExpression(initializer, BindType(fields[0].Type)); } - return new BoundStructInitializerNode(expression.Tokens, structType, structType, initializers); + return new BoundStructInitializerNode(expression.Tokens, BindType(structType), new BoundNubStructType(@struct.Namespace, @struct.Name), initializers); } private BoundUnaryExpressionNode BindUnaryExpression(UnaryExpressionNode expression) { var boundOperand = BindExpression(expression.Operand); - NubType? type = null; + BoundNubType? type = null; switch (expression.Operator) { case UnaryExpressionOperator.Negate: { - boundOperand = BindExpression(expression.Operand, NubPrimitiveType.I64); + boundOperand = BindExpression(expression.Operand, BoundNubPrimitiveType.I64); if (boundOperand.Type.IsNumber) { @@ -514,9 +540,9 @@ public sealed class Binder } case UnaryExpressionOperator.Invert: { - boundOperand = BindExpression(expression.Operand, NubPrimitiveType.Bool); + boundOperand = BindExpression(expression.Operand, BoundNubPrimitiveType.Bool); - type = new NubPrimitiveType(PrimitiveTypeKind.Bool); + type = new BoundNubPrimitiveType(PrimitiveTypeKind.Bool); break; } } @@ -529,46 +555,80 @@ public sealed class Binder return new BoundUnaryExpressionNode(expression.Tokens, type, expression.Operator, boundOperand); } - private NubType BindType(NubType type) + private BoundNubType BindType(NubType type) { - if (type is NubCustomType customType) + switch (type) { - var structs = _definitionTable.LookupStruct(customType.Namespace, customType.Name).ToArray(); - if (structs.Length > 1) + case NubCustomType customType: { - throw new BindException(Diagnostic.Error($"Struct {type} has multiple definitions").Build()); - } + var structs = _definitionTable.LookupStruct(customType.Namespace, customType.Name).ToArray(); + if (structs.Length > 1) + { + throw new BindException(Diagnostic.Error($"Struct {type} has multiple definitions").Build()); + } - var traits = _definitionTable.LookupTrait(customType.Namespace, customType.Name).ToArray(); - if (traits.Length > 1) - { - throw new BindException(Diagnostic.Error($"Trait {type} has multiple definitions").Build()); - } + var traits = _definitionTable.LookupTrait(customType.Namespace, customType.Name).ToArray(); + if (traits.Length > 1) + { + throw new BindException(Diagnostic.Error($"Trait {type} has multiple definitions").Build()); + } - if (structs.Length == 0 && traits.Length == 0) - { - throw new BindException(Diagnostic.Error($"Failed to resolve type {type} to a struct or trait").Build()); - } + if (structs.Length == 0 && traits.Length == 0) + { + throw new BindException(Diagnostic.Error($"Failed to resolve type {type} to a struct or trait").Build()); + } - if (structs.Length > 0 && traits.Length > 0) - { - throw new BindException(Diagnostic.Error($"Unable to determine if type {type} is a struct or trait").WithHelp($"Make {type} is not defined as bot a struct and trait").Build()); - } + if (structs.Length > 0 && traits.Length > 0) + { + throw new BindException(Diagnostic.Error($"Unable to determine if type {type} is a struct or trait").WithHelp($"Make {type} is not defined as bot a struct and trait").Build()); + } - if (structs.Length == 1) - { - return new NubStructType(customType.Namespace, customType.Name); - } + if (structs.Length == 1) + { + return new BoundNubStructType(customType.Namespace, customType.Name); + } - if (traits.Length == 1) - { - return new NubTraitType(customType.Namespace, customType.Name); - } + if (traits.Length == 1) + { + return new BoundNubTraitType(customType.Namespace, customType.Name); + } - throw new UnreachableException(); + throw new UnreachableException(); + } + case NubArrayType arrayType: + return new BoundNubArrayType(BindType(arrayType.ElementType)); + case NubCStringType: + return new BoundNubCStringType(); + case NubStringType: + return new BoundNubStringType(); + case NubFuncType funcType: + return new BoundNubFuncType(BindType(funcType.ReturnType), funcType.Parameters.Select(BindType).ToList()); + case NubPointerType pointerType: + return new BoundNubPointerType(BindType(pointerType.BaseType)); + case NubPrimitiveType primitiveType: + return new BoundNubPrimitiveType(primitiveType.Kind); + case NubVoidType: + return new BoundNubVoidType(); + default: + throw new ArgumentOutOfRangeException(nameof(type)); } + } - return type; + private NubType UnbindType(BoundNubType type) + { + return type switch + { + BoundNubArrayType arrayType => new NubArrayType(UnbindType(arrayType.ElementType)), + BoundNubCStringType => new NubCStringType(), + BoundNubStringType => new NubStringType(), + BoundNubStructType structType => new NubCustomType(structType.Namespace, structType.Name), + BoundNubTraitType traitType => new NubCustomType(traitType.Namespace, traitType.Name), + BoundNubFuncType funcType => new NubFuncType(UnbindType(funcType.ReturnType), funcType.Parameters.Select(UnbindType).ToList()), + BoundNubPointerType pointerType => new NubPointerType(UnbindType(pointerType.BaseType)), + BoundNubPrimitiveType primitiveType => new NubPrimitiveType(primitiveType.Kind), + BoundNubVoidType => new NubVoidType(), + _ => throw new ArgumentOutOfRangeException(nameof(type)) + }; } } diff --git a/src/compiler/Syntax/DefinitionTable.cs b/src/compiler/Syntax/DefinitionTable.cs index 421df90..c1b9d6d 100644 --- a/src/compiler/Syntax/DefinitionTable.cs +++ b/src/compiler/Syntax/DefinitionTable.cs @@ -37,16 +37,13 @@ public sealed class DefinitionTable return structNode.Fields.Where(x => x.Name == field); } - public IEnumerable LookupTraitImpl(NubType itemType) + public IEnumerable LookupTraitFuncImpl(NubType forType, string name) { return _topLevelNodes .OfType() - .Where(x => x.TraitType == itemType); - } - - public IEnumerable LookupTraitFuncImpl(TraitImplNode traitImpl, string name) - { - return traitImpl.Functions.Where(x => x.Name == name); + .Where(x => x.ForType == forType) + .SelectMany(x => x.Functions) + .Where(x => x.Name == name); } public IEnumerable LookupTrait(string @namespace, string name) @@ -97,16 +94,20 @@ public sealed class BoundDefinitionTable return structNode.Fields.First(x => x.Name == field); } - public BoundTraitImplNode LookupTraitImpl(NubType itemType) + public IEnumerable LookupTraitImpls(BoundNubType itemType) { return _topLevelNodes .OfType() - .First(x => x.TraitType == itemType); + .Where(x => x.ForType == itemType); } - public BoundTraitFuncImplNode LookupTraitFuncImpl(BoundTraitImplNode traitImpl, string name) + public BoundTraitFuncImplNode LookupTraitFuncImpl(BoundNubType forType, string name) { - return traitImpl.Functions.First(x => x.Name == name); + return _topLevelNodes + .OfType() + .Where(x => x.ForType == forType) + .SelectMany(x => x.Functions) + .First(x => x.Name == name); } public BoundTraitNode LookupTrait(string @namespace, string name) diff --git a/src/compiler/Syntax/Node/Definition.cs b/src/compiler/Syntax/Node/Definition.cs index 8ef707d..c9234de 100644 --- a/src/compiler/Syntax/Node/Definition.cs +++ b/src/compiler/Syntax/Node/Definition.cs @@ -3,7 +3,8 @@ using Syntax.Tokenization; namespace Syntax.Node; -public record FuncParameter(string Name, NubType Type); +public record FuncParameterNode(IEnumerable Tokens, string Name, NubType Type) : DefinitionNode(Tokens); +public record BoundFuncParameterNode(IEnumerable Tokens, string Name, BoundNubType Type) : DefinitionNode(Tokens); public abstract record TopLevelNode(IEnumerable Tokens, string Namespace) : Node(Tokens); public abstract record BoundTopLevelNode(IEnumerable Tokens, string Namespace) : BoundNode(Tokens); @@ -11,26 +12,26 @@ public abstract record BoundTopLevelNode(IEnumerable Tokens, string Names public abstract record DefinitionNode(IEnumerable Tokens) : Node(Tokens); public abstract record BoundDefinitionNode(IEnumerable Tokens) : BoundNode(Tokens); -public record LocalFuncNode(IEnumerable Tokens, string Namespace, string Name, List Parameters, BlockNode Body, NubType ReturnType, bool Exported) : TopLevelNode(Tokens, Namespace); -public record BoundLocalFuncNode(IEnumerable Tokens, string Namespace, string Name, List Parameters, BoundBlock Body, NubType ReturnType, bool Exported) : BoundTopLevelNode(Tokens, Namespace); +public record LocalFuncNode(IEnumerable Tokens, string Namespace, string Name, List Parameters, BlockNode Body, NubType ReturnType, bool Exported) : TopLevelNode(Tokens, Namespace); +public record BoundLocalFuncNode(IEnumerable Tokens, string Namespace, string Name, List Parameters, BoundBlock Body, BoundNubType ReturnType, bool Exported) : BoundTopLevelNode(Tokens, Namespace); -public record ExternFuncNode(IEnumerable Tokens, string Namespace, string Name, string CallName, List Parameters, NubType ReturnType) : TopLevelNode(Tokens, Namespace); -public record BoundExternFuncNode(IEnumerable Tokens, string Namespace, string Name, string CallName, List Parameters, NubType ReturnType) : BoundTopLevelNode(Tokens, Namespace); +public record ExternFuncNode(IEnumerable Tokens, string Namespace, string Name, string CallName, List Parameters, NubType ReturnType) : TopLevelNode(Tokens, Namespace); +public record BoundExternFuncNode(IEnumerable Tokens, string Namespace, string Name, string CallName, List Parameters, BoundNubType ReturnType) : BoundTopLevelNode(Tokens, Namespace); public record StructFieldNode(IEnumerable Tokens, int Index, string Name, NubType Type, Optional Value) : DefinitionNode(Tokens); public record StructNode(IEnumerable Tokens, string Namespace, string Name, List Fields) : TopLevelNode(Tokens, Namespace); -public record BoundStructFieldNode(IEnumerable Tokens, int Index, string Name, NubType Type, Optional Value) : BoundDefinitionNode(Tokens); +public record BoundStructFieldNode(IEnumerable Tokens, int Index, string Name, BoundNubType Type, Optional Value) : BoundDefinitionNode(Tokens); public record BoundStructNode(IEnumerable Tokens, string Namespace, string Name, List Fields) : BoundTopLevelNode(Tokens, Namespace); -public record TraitFuncNode(IEnumerable Tokens, string Name, List Parameters, NubType ReturnType) : DefinitionNode(Tokens); +public record TraitFuncNode(IEnumerable Tokens, string Name, List Parameters, NubType ReturnType) : DefinitionNode(Tokens); public record TraitNode(IEnumerable Tokens, string Namespace, string Name, List Functions) : TopLevelNode(Tokens, Namespace); -public record BoundTraitFuncNode(IEnumerable Tokens, string Name, List Parameters, NubType ReturnType) : BoundDefinitionNode(Tokens); +public record BoundTraitFuncNode(IEnumerable Tokens, string Name, List Parameters, BoundNubType ReturnType) : BoundDefinitionNode(Tokens); public record BoundTraitNode(IEnumerable Tokens, string Namespace, string Name, List Functions) : BoundTopLevelNode(Tokens, Namespace); -public record TraitFuncImplNode(IEnumerable Tokens, string Name, List Parameters, NubType ReturnType, BlockNode Body) : DefinitionNode(Tokens); +public record TraitFuncImplNode(IEnumerable Tokens, string Name, List Parameters, NubType ReturnType, BlockNode Body) : DefinitionNode(Tokens); public record TraitImplNode(IEnumerable Tokens, string Namespace, NubType TraitType, NubType ForType, List Functions) : TopLevelNode(Tokens, Namespace); -public record BoundTraitFuncImplNode(IEnumerable Tokens, string Name, List Parameters, NubType ReturnType, BoundBlock Body) : BoundDefinitionNode(Tokens); -public record BoundTraitImplNode(IEnumerable Tokens, string Namespace, NubType TraitType, NubType ForType, List Functions) : BoundTopLevelNode(Tokens, Namespace); \ No newline at end of file +public record BoundTraitFuncImplNode(IEnumerable Tokens, string Name, List Parameters, BoundNubType ReturnType, BoundBlock Body) : BoundDefinitionNode(Tokens); +public record BoundTraitImplNode(IEnumerable Tokens, string Namespace, BoundNubType TraitType, BoundNubType ForType, List Functions) : BoundTopLevelNode(Tokens, Namespace); \ No newline at end of file diff --git a/src/compiler/Syntax/Node/Expression.cs b/src/compiler/Syntax/Node/Expression.cs index 8925678..a1aac1c 100644 --- a/src/compiler/Syntax/Node/Expression.cs +++ b/src/compiler/Syntax/Node/Expression.cs @@ -24,44 +24,44 @@ public enum BinaryExpressionOperator } public abstract record ExpressionNode(IEnumerable Tokens) : Node(Tokens); -public abstract record BoundExpressionNode(IEnumerable Tokens, NubType Type) : BoundNode(Tokens); +public abstract record BoundExpressionNode(IEnumerable Tokens, BoundNubType Type) : BoundNode(Tokens); public record BinaryExpressionNode(IEnumerable Tokens, ExpressionNode Left, BinaryExpressionOperator Operator, ExpressionNode Right) : ExpressionNode(Tokens); -public record BoundBinaryExpressionNode(IEnumerable Tokens, NubType Type, BoundExpressionNode Left, BinaryExpressionOperator Operator, BoundExpressionNode Right) : BoundExpressionNode(Tokens, Type); +public record BoundBinaryExpressionNode(IEnumerable Tokens, BoundNubType Type, BoundExpressionNode Left, BinaryExpressionOperator Operator, BoundExpressionNode Right) : BoundExpressionNode(Tokens, Type); public record UnaryExpressionNode(IEnumerable Tokens, UnaryExpressionOperator Operator, ExpressionNode Operand) : ExpressionNode(Tokens); -public record BoundUnaryExpressionNode(IEnumerable Tokens, NubType Type, UnaryExpressionOperator Operator, BoundExpressionNode Operand) : BoundExpressionNode(Tokens, Type); +public record BoundUnaryExpressionNode(IEnumerable Tokens, BoundNubType Type, UnaryExpressionOperator Operator, BoundExpressionNode Operand) : BoundExpressionNode(Tokens, Type); public record FuncCallNode(IEnumerable Tokens, ExpressionNode Expression, List Parameters) : ExpressionNode(Tokens); -public record BoundFuncCallNode(IEnumerable Tokens, NubType Type, BoundExpressionNode Expression, List Parameters) : BoundExpressionNode(Tokens, Type); +public record BoundFuncCallNode(IEnumerable Tokens, BoundNubType Type, BoundExpressionNode Expression, List Parameters) : BoundExpressionNode(Tokens, Type); public record IdentifierNode(IEnumerable Tokens, Optional Namespace, string Name) : ExpressionNode(Tokens); -public record BoundVariableIdentNode(IEnumerable Tokens, NubType Type, string Name) : BoundExpressionNode(Tokens, Type); -public record BoundLocalFuncIdentNode(IEnumerable Tokens, NubType Type, string Namespace, string Name) : BoundExpressionNode(Tokens, Type); -public record BoundExternFuncIdentNode(IEnumerable Tokens, NubType Type, string Namespace, string Name) : BoundExpressionNode(Tokens, Type); +public record BoundVariableIdentNode(IEnumerable Tokens, BoundNubType Type, string Name) : BoundExpressionNode(Tokens, Type); +public record BoundLocalFuncIdentNode(IEnumerable Tokens, BoundNubType Type, string Namespace, string Name) : BoundExpressionNode(Tokens, Type); +public record BoundExternFuncIdentNode(IEnumerable Tokens, BoundNubType Type, string Namespace, string Name) : BoundExpressionNode(Tokens, Type); public record ArrayInitializerNode(IEnumerable Tokens, ExpressionNode Capacity, NubType ElementType) : ExpressionNode(Tokens); -public record BoundArrayInitializerNode(IEnumerable Tokens, NubType Type, BoundExpressionNode Capacity, NubType ElementType) : BoundExpressionNode(Tokens, Type); +public record BoundArrayInitializerNode(IEnumerable Tokens, BoundNubType Type, BoundExpressionNode Capacity, BoundNubType ElementType) : BoundExpressionNode(Tokens, Type); -public record ArrayIndexAccessNode(IEnumerable Tokens, ExpressionNode Array, ExpressionNode Index) : ExpressionNode(Tokens); -public record BoundArrayIndexAccessNode(IEnumerable Tokens, NubType Type, BoundExpressionNode Array, BoundExpressionNode Index) : BoundExpressionNode(Tokens, Type); +public record ArrayIndexAccessNode(IEnumerable Tokens, ExpressionNode Target, ExpressionNode Index) : ExpressionNode(Tokens); +public record BoundArrayIndexAccessNode(IEnumerable Tokens, BoundNubType Type, BoundExpressionNode Target, BoundExpressionNode Index) : BoundExpressionNode(Tokens, Type); -public record AnonymousFuncNode(IEnumerable Tokens, List Parameters, BlockNode Body, NubType ReturnType) : ExpressionNode(Tokens); -public record BoundAnonymousFuncNode(IEnumerable Tokens, NubType Type, List Parameters, BoundBlock Body, NubType ReturnType) : BoundExpressionNode(Tokens, Type); +public record AnonymousFuncNode(IEnumerable Tokens, List Parameters, BlockNode Body, NubType ReturnType) : ExpressionNode(Tokens); +public record BoundAnonymousFuncNode(IEnumerable Tokens, BoundNubType Type, List Parameters, BoundBlock Body, BoundNubType ReturnType) : BoundExpressionNode(Tokens, Type); public record AddressOfNode(IEnumerable Tokens, ExpressionNode Expression) : ExpressionNode(Tokens); -public record BoundAddressOfNode(IEnumerable Tokens, NubType Type, BoundExpressionNode Expression) : BoundExpressionNode(Tokens, Type); +public record BoundAddressOfNode(IEnumerable Tokens, BoundNubType Type, BoundExpressionNode Expression) : BoundExpressionNode(Tokens, Type); public record LiteralNode(IEnumerable Tokens, string Literal, LiteralKind Kind) : ExpressionNode(Tokens); -public record BoundLiteralNode(IEnumerable Tokens, NubType Type, string Literal, LiteralKind Kind) : BoundExpressionNode(Tokens, Type); +public record BoundLiteralNode(IEnumerable Tokens, BoundNubType Type, string Literal, LiteralKind Kind) : BoundExpressionNode(Tokens, Type); public record MemberAccessNode(IEnumerable Tokens, ExpressionNode Target, string Member) : ExpressionNode(Tokens); -public record BoundStructFieldAccessNode(IEnumerable Tokens, NubType Type, NubStructType StructType, BoundExpressionNode Target, string Field) : BoundExpressionNode(Tokens, Type); -public record BoundTraitImplFuncAccessNode(IEnumerable Tokens, NubType Type, BoundExpressionNode Target, string FuncName) : BoundExpressionNode(Tokens, Type); -public record BoundTraitFuncAccessNode(IEnumerable Tokens, NubType Type, NubTraitType TraitType, BoundExpressionNode Target, string FuncName) : BoundExpressionNode(Tokens, Type); +public record BoundStructFieldAccessNode(IEnumerable Tokens, BoundNubType Type, BoundNubStructType StructType, BoundExpressionNode Target, string Field) : BoundExpressionNode(Tokens, Type); +public record BoundTraitImplFuncAccessNode(IEnumerable Tokens, BoundNubType Type, BoundExpressionNode Target, string FuncName) : BoundExpressionNode(Tokens, Type); +public record BoundTraitFuncAccessNode(IEnumerable Tokens, BoundNubType Type, BoundNubTraitType TraitType, BoundExpressionNode Target, string FuncName) : BoundExpressionNode(Tokens, Type); public record StructInitializerNode(IEnumerable Tokens, NubType StructType, Dictionary Initializers) : ExpressionNode(Tokens); -public record BoundStructInitializerNode(IEnumerable Tokens, NubType Type, NubType StructType, Dictionary Initializers) : BoundExpressionNode(Tokens, Type); +public record BoundStructInitializerNode(IEnumerable Tokens, BoundNubType Type, BoundNubStructType StructType, Dictionary Initializers) : BoundExpressionNode(Tokens, Type); public record DereferenceNode(IEnumerable Tokens, ExpressionNode Expression) : ExpressionNode(Tokens); -public record BoundDereferenceNode(IEnumerable Tokens, NubType Type, BoundExpressionNode Expression) : BoundExpressionNode(Tokens, Type); \ No newline at end of file +public record BoundDereferenceNode(IEnumerable Tokens, BoundNubType Type, BoundExpressionNode Expression) : BoundExpressionNode(Tokens, Type); \ No newline at end of file diff --git a/src/compiler/Syntax/Node/Statement.cs b/src/compiler/Syntax/Node/Statement.cs index 250a294..04dd10d 100644 --- a/src/compiler/Syntax/Node/Statement.cs +++ b/src/compiler/Syntax/Node/Statement.cs @@ -20,7 +20,7 @@ public record IfNode(IEnumerable Tokens, ExpressionNode Condition, BlockN public record BoundIfNode(IEnumerable Tokens, BoundExpressionNode Condition, BoundBlock Body, Optional> Else) : BoundStatementNode(Tokens); public record VariableDeclarationNode(IEnumerable Tokens, string Name, Optional ExplicitType, Optional Assignment) : StatementNode(Tokens); -public record BoundVariableDeclarationNode(IEnumerable Tokens, string Name, Optional ExplicitType, Optional Assignment, NubType Type) : BoundStatementNode(Tokens); +public record BoundVariableDeclarationNode(IEnumerable Tokens, string Name, Optional Assignment, BoundNubType Type) : BoundStatementNode(Tokens); public record ContinueNode(IEnumerable Tokens) : StatementNode(Tokens); public record BoundContinueNode(IEnumerable Tokens) : BoundStatementNode(Tokens); diff --git a/src/compiler/Syntax/NubBoundType.cs b/src/compiler/Syntax/NubBoundType.cs new file mode 100644 index 0000000..52aa797 --- /dev/null +++ b/src/compiler/Syntax/NubBoundType.cs @@ -0,0 +1,191 @@ +using System.Diagnostics.CodeAnalysis; + +namespace Syntax; + +public abstract class BoundNubType : IEquatable +{ + public bool Is8BitInteger => this is BoundNubPrimitiveType { Kind: PrimitiveTypeKind.I8 or PrimitiveTypeKind.U8 }; + public bool Is16BitInteger => this is BoundNubPrimitiveType { Kind: PrimitiveTypeKind.I16 or PrimitiveTypeKind.U16 }; + public bool Is32BitInteger => this is BoundNubPrimitiveType { Kind: PrimitiveTypeKind.I32 or PrimitiveTypeKind.U32 }; + public bool Is64BitInteger => this is BoundNubPrimitiveType { Kind: PrimitiveTypeKind.I64 or PrimitiveTypeKind.U64 }; + + public bool IsSignedInteger => this is BoundNubPrimitiveType { Kind: PrimitiveTypeKind.I8 or PrimitiveTypeKind.I16 or PrimitiveTypeKind.I32 or PrimitiveTypeKind.I64 }; + public bool IsUnsignedInteger => this is BoundNubPrimitiveType { Kind: PrimitiveTypeKind.U8 or PrimitiveTypeKind.U16 or PrimitiveTypeKind.U32 or PrimitiveTypeKind.U64 }; + public bool IsInteger => IsSignedInteger || IsUnsignedInteger; + + public bool IsFloat32 => this is BoundNubPrimitiveType { Kind: PrimitiveTypeKind.F32 }; + public bool IsFloat64 => this is BoundNubPrimitiveType { Kind: PrimitiveTypeKind.F64 }; + public bool IsFloat => IsFloat32 || IsFloat64; + + public bool IsNumber => IsFloat || IsInteger; + + public bool IsVoid => this is BoundNubVoidType; + public bool IsString => this is BoundNubStringType; + public bool IsCString => this is BoundNubCStringType; + public bool IsBool => this is BoundNubPrimitiveType { Kind: PrimitiveTypeKind.Bool }; + + public override bool Equals(object? obj) => obj is BoundNubType other && Equals(other); + + public abstract bool Equals(BoundNubType? other); + public abstract override int GetHashCode(); + public abstract override string ToString(); + + public static bool operator ==(BoundNubType? left, BoundNubType? right) => Equals(left, right); + public static bool operator !=(BoundNubType? left, BoundNubType? right) => !Equals(left, right); +} + +public abstract class BoundNubComplexType : BoundNubType; + +public abstract class BoundNubSimpleType : BoundNubType; + +public class BoundNubCStringType : BoundNubComplexType +{ + public override string ToString() => "cstring"; + public override bool Equals(BoundNubType? other) => other is BoundNubCStringType; + public override int GetHashCode() => HashCode.Combine(typeof(BoundNubCStringType)); +} + +public class BoundNubStringType : BoundNubComplexType +{ + public override string ToString() => "string"; + public override bool Equals(BoundNubType? other) => other is BoundNubStringType; + public override int GetHashCode() => HashCode.Combine(typeof(BoundNubStringType)); +} + +public class BoundNubFuncType(BoundNubType returnType, List parameters) : BoundNubSimpleType +{ + public BoundNubType ReturnType { get; } = returnType; + public List Parameters { get; } = parameters; + + public override string ToString() => $"func({string.Join(", ", Parameters)}): {ReturnType}"; + + public override bool Equals(BoundNubType? other) => other is BoundNubFuncType func && ReturnType.Equals(func.ReturnType) && Parameters.SequenceEqual(func.Parameters); + + public override int GetHashCode() + { + var hash = new HashCode(); + hash.Add(typeof(BoundNubFuncType)); + hash.Add(ReturnType); + foreach (var param in Parameters) + { + hash.Add(param); + } + + return hash.ToHashCode(); + } +} + +public class BoundNubStructType(string @namespace, string name) : BoundNubComplexType +{ + public string Namespace { get; } = @namespace; + public string Name { get; } = name; + + public override string ToString() => $"{Namespace}::{Name}"; + + public override bool Equals(BoundNubType? other) => other is BoundNubStructType custom && Namespace == custom.Namespace && Name == custom.Name; + public override int GetHashCode() => HashCode.Combine(typeof(BoundNubStructType), Namespace, Name); +} + +public class BoundNubTraitType(string @namespace, string name) : BoundNubComplexType +{ + public string Namespace { get; } = @namespace; + public string Name { get; } = name; + + public override string ToString() => $"{Namespace}::{Name}"; + + public override bool Equals(BoundNubType? other) => other is BoundNubTraitType custom && Namespace == custom.Namespace && Name == custom.Name; + public override int GetHashCode() => HashCode.Combine(typeof(BoundNubTraitType), Namespace, Name); +} + +public class BoundNubPointerType(BoundNubType baseType) : BoundNubSimpleType +{ + public BoundNubType BaseType { get; } = baseType; + + public override string ToString() => "^" + BaseType; + + public override bool Equals(BoundNubType? other) => other is BoundNubPointerType pointer && BaseType.Equals(pointer.BaseType); + public override int GetHashCode() => HashCode.Combine(typeof(BoundNubPointerType), BaseType); +} + +public class BoundNubArrayType(BoundNubType elementType) : BoundNubComplexType +{ + public BoundNubType ElementType { get; } = elementType; + + public override string ToString() => "[]" + ElementType; + + public override bool Equals(BoundNubType? other) => other is BoundNubArrayType array && ElementType.Equals(array.ElementType); + public override int GetHashCode() => HashCode.Combine(typeof(BoundNubArrayType), ElementType); +} + +public class BoundNubVoidType : BoundNubSimpleType +{ + public override string ToString() => "void"; + public override bool Equals(BoundNubType? other) => other is BoundNubVoidType; + public override int GetHashCode() => HashCode.Combine(typeof(BoundNubVoidType)); +} + +public class BoundNubPrimitiveType(PrimitiveTypeKind kind) : BoundNubSimpleType +{ + public PrimitiveTypeKind Kind { get; } = kind; + + public static BoundNubPrimitiveType I64 => new(PrimitiveTypeKind.I64); + public static BoundNubPrimitiveType I32 => new(PrimitiveTypeKind.I32); + public static BoundNubPrimitiveType I16 => new(PrimitiveTypeKind.I16); + public static BoundNubPrimitiveType I8 => new(PrimitiveTypeKind.I8); + + public static BoundNubPrimitiveType U64 => new(PrimitiveTypeKind.U64); + public static BoundNubPrimitiveType U32 => new(PrimitiveTypeKind.U32); + public static BoundNubPrimitiveType U16 => new(PrimitiveTypeKind.U16); + public static BoundNubPrimitiveType U8 => new(PrimitiveTypeKind.U8); + + public static BoundNubPrimitiveType F64 => new(PrimitiveTypeKind.F64); + public static BoundNubPrimitiveType F32 => new(PrimitiveTypeKind.F32); + + public static BoundNubPrimitiveType Bool => new(PrimitiveTypeKind.Bool); + + public static bool TryParse(string s, [NotNullWhen(true)] out PrimitiveTypeKind? kind) + { + kind = s switch + { + "i64" => PrimitiveTypeKind.I64, + "i32" => PrimitiveTypeKind.I32, + "i16" => PrimitiveTypeKind.I16, + "i8" => PrimitiveTypeKind.I8, + "u64" => PrimitiveTypeKind.U64, + "u32" => PrimitiveTypeKind.U32, + "u16" => PrimitiveTypeKind.U16, + "u8" => PrimitiveTypeKind.U8, + "f64" => PrimitiveTypeKind.F64, + "f32" => PrimitiveTypeKind.F32, + "bool" => PrimitiveTypeKind.Bool, + _ => null + }; + + return kind != null; + } + + public override string ToString() + { + return Kind switch + { + PrimitiveTypeKind.I8 => "i8", + PrimitiveTypeKind.I16 => "i16", + PrimitiveTypeKind.I32 => "i32", + PrimitiveTypeKind.I64 => "i64", + + PrimitiveTypeKind.U8 => "u8", + PrimitiveTypeKind.U16 => "u16", + PrimitiveTypeKind.U32 => "u32", + PrimitiveTypeKind.U64 => "u64", + + PrimitiveTypeKind.F32 => "f32", + PrimitiveTypeKind.F64 => "f64", + + PrimitiveTypeKind.Bool => "bool", + _ => throw new ArgumentOutOfRangeException(nameof(kind), Kind, null) + }; + } + + public override bool Equals(BoundNubType? other) => other is BoundNubPrimitiveType primitive && primitive.Kind == Kind; + public override int GetHashCode() => HashCode.Combine(typeof(BoundNubPrimitiveType), Kind.GetHashCode()); +} \ No newline at end of file diff --git a/src/compiler/Syntax/NubType.cs b/src/compiler/Syntax/NubType.cs index e9a7501..52f10d1 100644 --- a/src/compiler/Syntax/NubType.cs +++ b/src/compiler/Syntax/NubType.cs @@ -86,18 +86,6 @@ public class NubCustomType(string @namespace, string name) : NubComplexType public override int GetHashCode() => HashCode.Combine(typeof(NubCustomType), Namespace, Name); } -public class NubStructType(string @namespace, string name) : NubCustomType(@namespace, name) -{ - public override bool Equals(NubType? other) => other is NubStructType custom && Namespace == custom.Namespace && Name == custom.Name; - public override int GetHashCode() => HashCode.Combine(typeof(NubStructType), Namespace, Name); -} - -public class NubTraitType(string @namespace, string name) : NubCustomType(@namespace, name) -{ - public override bool Equals(NubType? other) => other is NubTraitType custom && Namespace == custom.Namespace && Name == custom.Name; - public override int GetHashCode() => HashCode.Combine(typeof(NubTraitType), Namespace, Name); -} - public class NubPointerType(NubType baseType) : NubSimpleType { public NubType BaseType { get; } = baseType; diff --git a/src/compiler/Syntax/Parsing/Parser.cs b/src/compiler/Syntax/Parsing/Parser.cs index 570528a..3726d1e 100644 --- a/src/compiler/Syntax/Parsing/Parser.cs +++ b/src/compiler/Syntax/Parsing/Parser.cs @@ -89,7 +89,7 @@ public sealed class Parser private TopLevelNode ParseFunc(int startIndex, List modifiers) { var name = ExpectIdentifier(); - List parameters = []; + List parameters = []; ExpectSymbol(Symbol.OpenParen); @@ -184,7 +184,7 @@ public sealed class Parser ExpectSymbol(Symbol.Func); var funcName = ExpectIdentifier().Value; - var parameters = new List(); + var parameters = new List(); ExpectSymbol(Symbol.OpenParen); while (!TryExpectSymbol(Symbol.CloseParen)) @@ -223,9 +223,9 @@ public sealed class Parser var funcStartIndex = _tokenIndex; ExpectSymbol(Symbol.Func); var functionName = ExpectIdentifier().Value; - var parameters = new List + var parameters = new List { - new("this", forType) + new([], "this", forType) }; ExpectSymbol(Symbol.OpenParen); @@ -254,13 +254,14 @@ public sealed class Parser return new TraitImplNode(GetTokensForNode(startIndex), _namespace, traitType, forType, functions); } - private FuncParameter ParseFuncParameter() + private FuncParameterNode ParseFuncParameter() { + var startIndex = _tokenIndex; var name = ExpectIdentifier(); ExpectSymbol(Symbol.Colon); var type = ParseType(); - return new FuncParameter(name.Value, type); + return new FuncParameterNode(GetTokensForNode(startIndex), name.Value, type); } private StatementNode ParseStatement() @@ -494,7 +495,7 @@ public sealed class Parser { case Symbol.Func: { - List parameters = []; + List parameters = []; ExpectSymbol(Symbol.OpenParen); while (!TryExpectSymbol(Symbol.CloseParen)) {