From 5515c4aed3bd6ad92fdddd531d5838e716b7cad8 Mon Sep 17 00:00:00 2001 From: nub31 Date: Thu, 26 Jun 2025 11:50:37 +0200 Subject: [PATCH] ... --- example/c.nub | 2 +- example/main.nub | 36 ++-- src/CLI/CLI.csproj | 4 +- src/CLI/Runtime/nub_cstring.s | 17 ++ src/CLI/Runtime/nub_mem.s | 1 + src/CLI/Runtime/nub_string.s | 102 +++------- src/Generation/QBE/QBEGenerator.cs | 230 ++++++++++++++-------- src/Syntax/Parsing/Node/Expression.cs | 2 +- src/Syntax/Parsing/Parser.cs | 2 +- src/Syntax/Typing/Binder.cs | 6 +- src/Syntax/Typing/BoundNode/Expression.cs | 2 +- src/Syntax/Typing/NubType.cs | 44 +++-- 12 files changed, 255 insertions(+), 193 deletions(-) create mode 100644 src/CLI/Runtime/nub_cstring.s diff --git a/example/c.nub b/example/c.nub index c24b1d3..8347d6a 100644 --- a/example/c.nub +++ b/example/c.nub @@ -1,4 +1,4 @@ namespace c -// extern func printf(fmt: ^u8, ...args: any): void +extern func printf(fmt: cstring, arg: u64): void extern func puts(fmt: cstring) diff --git a/example/main.nub b/example/main.nub index c1ded04..6b487b5 100644 --- a/example/main.nub +++ b/example/main.nub @@ -5,35 +5,39 @@ struct Human { } export func main(args: []cstring): i64 { - let human: Human + // let human: Human - human = alloc Human { - name = "member" - } + // human = alloc Human { + // name = "member" + // } - c::puts(human.name) + // c::puts(human.name) - c::puts("literal") + // c::puts("literal") - let x: cstring + // let x: cstring - x = "variable" + // x = "variable" - c::puts(x) + // c::puts(x) - let y: func(cstring) + // let y: func(cstring) - y = c::puts + // y = c::puts - y("proxy") + // y("proxy") - func(){ c::puts("anon") }() + // func(){ c::puts("anon") }() - let z: func() + // let z: func() - z = func() { c::puts("anon variable") } + // z = func() { c::puts("anon variable") } - z() + // z() + + c::printf("%d\n", "test".count) + + // c::puts("test") return 0 } diff --git a/src/CLI/CLI.csproj b/src/CLI/CLI.csproj index b1f4bc4..c8dff8b 100644 --- a/src/CLI/CLI.csproj +++ b/src/CLI/CLI.csproj @@ -14,13 +14,11 @@ - - - + diff --git a/src/CLI/Runtime/nub_cstring.s b/src/CLI/Runtime/nub_cstring.s new file mode 100644 index 0000000..8acef4f --- /dev/null +++ b/src/CLI/Runtime/nub_cstring.s @@ -0,0 +1,17 @@ +.intel_syntax noprefix + +.text +.globl nub_cstring_length +# func nub_cstring_length(string: cstring): u64 +nub_cstring_length: + xor rax, rax + +count_loop: + cmp byte ptr [rdi + rax], 0 + je done + + inc rax + jmp count_loop + +done: + ret diff --git a/src/CLI/Runtime/nub_mem.s b/src/CLI/Runtime/nub_mem.s index d2b5f72..27cf71c 100644 --- a/src/CLI/Runtime/nub_mem.s +++ b/src/CLI/Runtime/nub_mem.s @@ -6,6 +6,7 @@ nub_memcpy: mov rcx, rdx rep movsb + ret .text .globl nub_memset diff --git a/src/CLI/Runtime/nub_string.s b/src/CLI/Runtime/nub_string.s index 879e4f8..dccbd5d 100644 --- a/src/CLI/Runtime/nub_string.s +++ b/src/CLI/Runtime/nub_string.s @@ -1,80 +1,32 @@ .intel_syntax noprefix -.equ SYS_MMAP, 9 - .text -.globl nub_strlen -# func nub_strlen(string: cstring): u64 -nub_strlen: - test rdi, rdi - jz null_string - xor rax, rax -strlen_loop: - cmp byte ptr [rdi + rax], 0 - je strlen_exit +.globl nub_string_length +# func nub_string_length(string: string): u64 +nub_string_length: + mov rsi, [rdi] # Length of string in bytes + + add rdi, 8 # Start of bytes + xor rax, rax # Character count + xor rdx, rdx # Current byte position + + test rsi, rsi + jz _done + +_count_loop: + cmp rdx, rsi + jge _done + + mov dl, [rdi + rdx] + and dl, 0b11000000 + cmp dl, 0b10000000 + je _skip_byte + inc rax - jmp strlen_loop -null_string: - xor rax, rax -strlen_exit: - ret - -.text -.globl nub_cstring_to_string -# func nub_cstring_to_string(string: cstring): []u8 -nub_cstring_to_string: - push rbx - push r12 - push r13 - - mov rbx, rdi # Save original pointer - call nub_strlen - mov r12, rax # r12 = string length - - # Calculate total space needed: 8 bytes (length) + string length - mov r13, r12 - add r13, 8 # r13 = total bytes needed - - # Round up to page size (4096 bytes) for mmap - add r13, 4095 # Add page_size - 1 - and r13, -4096 # Align to page boundary - - mov rax, SYS_MMAP - xor rdi, rdi # addr = 0 (let kernel choose) - mov rsi, r13 # length = aligned size - mov rdx, 3 # prot = PROT_READ | PROT_WRITE - mov r10, 34 # flags = MAP_PRIVATE | MAP_ANONYMOUS (0x22) - mov r8, -1 # fd = -1 - xor r9, r9 # offset = 0 - syscall - - # Check if mmap failed - cmp rax, -1 - je mmap_failed - - mov r13, rax # r13 = pointer to mapped memory - - # Store length at beginning of mapped memory - mov [r13], r12 # Store string length - - # Copy string data if not empty - test r12, r12 # Check if length is 0 - jz copy_done - - lea rdi, [r13 + 8] - mov rsi, rbx - mov rcx, r12 - call nub_memcpy - -copy_done: - mov rax, r13 - jmp function_exit - -mmap_failed: - xor rax, rax - -function_exit: - pop r13 - pop r12 - pop rbx + +_skip_byte: + inc rdx + jmp _count_loop + +_done: ret diff --git a/src/Generation/QBE/QBEGenerator.cs b/src/Generation/QBE/QBEGenerator.cs index 52cf3be..d8850c6 100644 --- a/src/Generation/QBE/QBEGenerator.cs +++ b/src/Generation/QBE/QBEGenerator.cs @@ -16,6 +16,7 @@ public static class QBEGenerator private static StringBuilder _builder = new(); private static List _cStringLiterals = []; + private static List _stringLiterals = []; private static Stack _breakLabels = []; private static Stack _continueLabels = []; private static Queue<(BoundAnonymousFuncNode Func, string Name)> _anonymousFunctions = []; @@ -25,6 +26,7 @@ public static class QBEGenerator private static int _labelIndex; private static int _anonymousFuncIndex; private static int _cStringLiteralIndex; + private static int _stringLiteralIndex; private static bool _codeIsReachable = true; public static string Emit(BoundSyntaxTree syntaxTree, BoundDefinitionTable definitionTable) @@ -34,6 +36,7 @@ public static class QBEGenerator _builder = new StringBuilder(); _cStringLiterals = []; + _stringLiterals = []; _breakLabels = []; _continueLabels = []; _anonymousFunctions = []; @@ -43,6 +46,7 @@ public static class QBEGenerator _labelIndex = 0; _anonymousFuncIndex = 0; _cStringLiteralIndex = 0; + _stringLiteralIndex = 0; _codeIsReachable = true; foreach (var structDef in _definitionTable.GetStructs()) @@ -68,6 +72,12 @@ public static class QBEGenerator _builder.AppendLine($"data {cStringLiteral.Name} = {{ b \"{cStringLiteral.Value}\", b 0 }}"); } + foreach (var stringLiteral in _stringLiterals) + { + var bytes = Encoding.UTF8.GetBytes(stringLiteral.Value).Select(b => $"b {b}"); + _builder.AppendLine($"data {stringLiteral.Name} = {{ l {stringLiteral.Value.Length}, {string.Join(", ", bytes)} }}"); + } + return _builder.ToString(); } @@ -86,6 +96,11 @@ public static class QBEGenerator return $"$cstring{++_cStringLiteralIndex}"; } + private static string StringName() + { + return $"$string{++_stringLiteralIndex}"; + } + private static string FuncName(BoundFuncDefinition funcDef) { return funcDef switch @@ -128,6 +143,7 @@ public static class QBEGenerator NubFixedArrayType => "storel", NubFuncType => "storel", NubCStringType => "storel", + NubStringType => "storel", _ => throw new NotSupportedException($"'{type}' type cannot be used in store instructions") }; } @@ -157,6 +173,7 @@ public static class QBEGenerator NubFixedArrayType => "loadl", NubFuncType => "loadl", NubCStringType => "loadl", + NubStringType => "loadl", _ => throw new NotSupportedException($"'{type}' type cannot be used in load instructions") }; } @@ -186,6 +203,7 @@ public static class QBEGenerator NubFixedArrayType => "=l", NubFuncType => "=l", NubCStringType => "=l", + NubStringType => "=l", _ => throw new NotSupportedException($"'{type}' type cannot be used in variables") }; } @@ -213,6 +231,7 @@ public static class QBEGenerator case NubPointerType: case NubArrayType: case NubCStringType: + case NubStringType: case NubFuncType: { return 8; @@ -241,12 +260,10 @@ public static class QBEGenerator { return primitiveType.Kind switch { - PrimitiveTypeKind.I64 or PrimitiveTypeKind.U64 => 8, - PrimitiveTypeKind.I32 or PrimitiveTypeKind.U32 or PrimitiveTypeKind.Bool => 4, + PrimitiveTypeKind.I64 or PrimitiveTypeKind.U64 or PrimitiveTypeKind.F64 => 8, + PrimitiveTypeKind.I32 or PrimitiveTypeKind.U32 or PrimitiveTypeKind.F32 or PrimitiveTypeKind.Bool => 4, PrimitiveTypeKind.I16 or PrimitiveTypeKind.U16 => 2, PrimitiveTypeKind.I8 or PrimitiveTypeKind.U8 => 1, - PrimitiveTypeKind.F64 => 8, - PrimitiveTypeKind.F32 => 4, _ => throw new ArgumentOutOfRangeException() }; } @@ -273,6 +290,7 @@ public static class QBEGenerator case NubPointerType: case NubArrayType: case NubCStringType: + case NubStringType: case NubFuncType: { return 8; @@ -354,6 +372,7 @@ public static class QBEGenerator NubFixedArrayType => "l", NubFuncType => "l", NubCStringType => "l", + NubStringType => "l", _ => throw new NotSupportedException($"'{returnType}' type cannot be used as a function return type") }); _builder.Append(' '); @@ -386,6 +405,7 @@ public static class QBEGenerator NubFixedArrayType => "l", NubFuncType => "l", NubCStringType => "l", + NubStringType => "l", _ => throw new NotSupportedException($"'{parameter.Type}' type cannot be used as a function parameter type") }; @@ -424,7 +444,7 @@ public static class QBEGenerator } } - parameterVars.Add(new Variable(parameter.Name, new Val(parameterName, parameter.Type))); + parameterVars.Add(new Variable(parameter.Name, new Val(parameterName, parameter.Type, ValKind.Immediate))); } EmitBlock(body, parameterVars); @@ -468,6 +488,7 @@ public static class QBEGenerator NubFixedArrayType fixedArrayType => $"b {SizeOf(fixedArrayType)}", NubFuncType => "l", NubCStringType => "l", + NubStringType => "l", _ => throw new NotSupportedException($"'{structDefinitionField.Type}' type cannot be used in structs") }; _builder.Append(qbeType + ", "); @@ -657,7 +678,7 @@ public static class QBEGenerator { var tmp = VarName(); _builder.AppendLine($" {tmp} =l alloc8 {SizeOf(variableDeclaration.Type)}"); - _variables.Push(new Variable(variableDeclaration.Name, new Val(tmp, variableDeclaration.Type))); + _variables.Push(new Variable(variableDeclaration.Name, new Val(tmp, variableDeclaration.Type, ValKind.Pointer))); } private static void EmitVariableAssignment(BoundVariableAssignmentNode variableAssignment) @@ -741,7 +762,7 @@ public static class QBEGenerator var pointer = EmitArrayIndexPointer(arrayIndexAccess); var outputName = VarName(); _builder.AppendLine($" {outputName} {QBEAssign(arrayIndexAccess.Type)} {QBELoad(arrayIndexAccess.Type)} {pointer}"); - return new Val(outputName, arrayIndexAccess.Type); + return new Val(outputName, arrayIndexAccess.Type, ValKind.Immediate); } private static void EmitArrayBoundsCheck(string array, string index) @@ -786,7 +807,7 @@ public static class QBEGenerator _builder.AppendLine($" {dataPointer} =l add {arrayPointer}, 8"); _builder.AppendLine($" call $nub_memset(l {dataPointer}, w 0, l {capacityInBytes})"); - return new Val(arrayPointer, arrayInitializer.Type); + return new Val(arrayPointer, arrayInitializer.Type, ValKind.Immediate); } private static Val EmitDereference(BoundDereferenceNode dereference) @@ -794,7 +815,7 @@ public static class QBEGenerator var result = EmitUnwrap(EmitExpression(dereference.Expression)); var outputName = VarName(); _builder.AppendLine($" {outputName} {QBEAssign(dereference.Type)} {QBELoad(dereference.Type)} {result}"); - return new Val(outputName, dereference.Type); + return new Val(outputName, dereference.Type, ValKind.Immediate); } private static Val EmitAddressOf(BoundAddressOfNode addressOf) @@ -802,22 +823,27 @@ public static class QBEGenerator switch (addressOf.Expression) { case BoundArrayIndexAccessNode arrayIndexAccess: + { var pointer = EmitArrayIndexPointer(arrayIndexAccess); - return new Val(pointer, addressOf.Type); + return new Val(pointer, addressOf.Type, ValKind.Immediate); + } case BoundDereferenceNode dereference: + { return EmitExpression(dereference.Expression); + } case BoundIdentifierNode identifier: + { if (identifier.Namespace.HasValue) { throw new NotSupportedException("There is nothing to address in another namespace"); } return _variables.Single(x => x.Name == identifier.Name).Val; - case BoundMemberAccessNode memberAccess: - var ptr = EmitMemberAccessPointer(memberAccess); - return new Val(ptr, addressOf.Type); + } default: + { throw new ArgumentOutOfRangeException(); + } } } @@ -826,7 +852,7 @@ public static class QBEGenerator var left = EmitUnwrap(EmitExpression(binaryExpression.Left)); var right = EmitUnwrap(EmitExpression(binaryExpression.Right)); var outputName = VarName(); - var output = new Val(outputName, binaryExpression.Type); + var output = new Val(outputName, binaryExpression.Type, ValKind.Immediate); switch (binaryExpression.Operator) { @@ -1052,44 +1078,80 @@ public static class QBEGenerator private static Val EmitLiteral(BoundLiteralNode literal) { - if (literal.Type.IsInteger) - { - switch (literal.Kind) - { - case LiteralKind.Integer: - return new Val(literal.Literal, literal.Type, ValKind.Literal); - case LiteralKind.Float: - return new Val(literal.Literal.Split(".").First(), literal.Type, ValKind.Literal); - default: - throw new ArgumentOutOfRangeException(); - } - } - - if (literal.Type.IsFloat64) - { - var value = double.Parse(literal.Literal, CultureInfo.InvariantCulture); - var bits = BitConverter.DoubleToInt64Bits(value); - return new Val(bits.ToString(), literal.Type, ValKind.Literal); - } - - if (literal.Type.IsFloat32) - { - var value = float.Parse(literal.Literal, CultureInfo.InvariantCulture); - var bits = BitConverter.SingleToInt32Bits(value); - return new Val(bits.ToString(), literal.Type, ValKind.Literal); - } - switch (literal.Kind) { + case LiteralKind.Integer: + { + if (literal.Type.IsFloat32) + { + var value = float.Parse(literal.Literal, CultureInfo.InvariantCulture); + var bits = BitConverter.SingleToInt32Bits(value); + return new Val(bits.ToString(), literal.Type, ValKind.Immediate); + } + + if (literal.Type.IsFloat64) + { + var value = double.Parse(literal.Literal, CultureInfo.InvariantCulture); + var bits = BitConverter.DoubleToInt64Bits(value); + return new Val(bits.ToString(), literal.Type, ValKind.Immediate); + } + + if (literal.Type.IsInteger) + { + return new Val(literal.Literal, literal.Type, ValKind.Immediate); + } + break; + } + case LiteralKind.Float: + { + if (literal.Type.IsInteger) + { + return new Val(literal.Literal.Split(".").First(), literal.Type, ValKind.Immediate); + } + + if (literal.Type.IsFloat32) + { + var value = float.Parse(literal.Literal, CultureInfo.InvariantCulture); + var bits = BitConverter.SingleToInt32Bits(value); + return new Val(bits.ToString(), literal.Type, ValKind.Immediate); + } + + if (literal.Type.IsFloat64) + { + var value = double.Parse(literal.Literal, CultureInfo.InvariantCulture); + var bits = BitConverter.DoubleToInt64Bits(value); + return new Val(bits.ToString(), literal.Type, ValKind.Immediate); + } + break; + } case LiteralKind.String: - var cStringLiteral = new CStringLiteral(literal.Literal, CStringName()); - _cStringLiterals.Add(cStringLiteral); - return new Val(cStringLiteral.Name, literal.Type, ValKind.Literal); + { + if (literal.Type.IsString) + { + var stringLiteral = new StringLiteral(literal.Literal, StringName()); + _stringLiterals.Add(stringLiteral); + return new Val(stringLiteral.Name, literal.Type, ValKind.Immediate); + } + + if (literal.Type.IsCString) + { + var cStringLiteral = new CStringLiteral(literal.Literal, CStringName()); + _cStringLiterals.Add(cStringLiteral); + return new Val(cStringLiteral.Name, literal.Type, ValKind.Immediate); + } + break; + } case LiteralKind.Bool: - return new Val(bool.Parse(literal.Literal) ? "1" : "0", literal.Type, ValKind.Literal); - default: - throw new ArgumentOutOfRangeException(); + { + if (literal.Type.IsBool) + { + return new Val(bool.Parse(literal.Literal) ? "1" : "0", literal.Type, ValKind.Immediate); + } + break; + } } + + throw new NotSupportedException($"Cannot create literal of kind '{literal.Kind}' for type {literal.Type}"); } private static Val EmitStructInitializer(BoundStructInitializerNode structInitializer) @@ -1124,7 +1186,7 @@ public static class QBEGenerator } } - return new Val(output, structInitializer.StructType); + return new Val(output, structInitializer.StructType, ValKind.Immediate); } private static Val EmitUnaryExpression(BoundUnaryExpressionNode unaryExpression) @@ -1140,16 +1202,16 @@ public static class QBEGenerator { case NubPrimitiveType { Kind: PrimitiveTypeKind.I64 }: _builder.AppendLine($" {outputName} =l neg {operand}"); - return new Val(outputName, unaryExpression.Type); + return new Val(outputName, unaryExpression.Type, ValKind.Immediate); case NubPrimitiveType { Kind: PrimitiveTypeKind.I32 or PrimitiveTypeKind.I16 or PrimitiveTypeKind.I8 }: _builder.AppendLine($" {outputName} =w neg {operand}"); - return new Val(outputName, unaryExpression.Type); + return new Val(outputName, unaryExpression.Type, ValKind.Immediate); case NubPrimitiveType { Kind: PrimitiveTypeKind.F64 }: _builder.AppendLine($" {outputName} =d neg {operand}"); - return new Val(outputName, unaryExpression.Type); + return new Val(outputName, unaryExpression.Type, ValKind.Immediate); case NubPrimitiveType { Kind: PrimitiveTypeKind.F32 }: _builder.AppendLine($" {outputName} =s neg {operand}"); - return new Val(outputName, unaryExpression.Type); + return new Val(outputName, unaryExpression.Type, ValKind.Immediate); } break; @@ -1160,7 +1222,7 @@ public static class QBEGenerator { case NubPrimitiveType { Kind: PrimitiveTypeKind.Bool }: _builder.AppendLine($" {outputName} =w xor {operand}, 1"); - return new Val(outputName, unaryExpression.Type); + return new Val(outputName, unaryExpression.Type, ValKind.Immediate); } break; @@ -1174,43 +1236,50 @@ public static class QBEGenerator throw new NotSupportedException($"Unary operator {unaryExpression.Operator} for type {unaryExpression.Operand.Type} not supported"); } - private static string EmitMemberAccessPointer(BoundMemberAccessNode memberAccess) + private static Val EmitMemberAccess(BoundMemberAccessNode memberAccess) { var item = EmitUnwrap(EmitExpression(memberAccess.Expression)); + var output = VarName(); + switch (memberAccess.Expression.Type) { case NubArrayType: { if (memberAccess.Member == "count") { - return item; + _builder.AppendLine($" {output} =l loadl {item}"); + break; } - - throw new UnreachableException(nameof(memberAccess.Member)); + + throw new UnreachableException(); + } + case NubStringType: + { + _builder.AppendLine($" {output} =l call $nub_string_length(l {item})"); + break; + } + case NubCStringType: + { + _builder.AppendLine($" {output} =l call $nub_cstring_length(l {item})"); + break; } case NubStructType structType: { var structDefinition = _definitionTable.LookupStruct(structType.Namespace, structType.Name).GetValue(); var offset = OffsetOf(structDefinition, memberAccess.Member); - + var offsetName = VarName(); _builder.AppendLine($" {offsetName} =l add {item}, {offset}"); - return offsetName; + _builder.AppendLine($" {output} {QBEAssign(memberAccess.Type)} {QBELoad(memberAccess.Type)} {item}"); + break; } default: { - throw new ArgumentOutOfRangeException(nameof(memberAccess.Expression.Type)); + throw new ArgumentOutOfRangeException(); } } - } - - private static Val EmitMemberAccess(BoundMemberAccessNode memberAccess) - { - var pointer = EmitMemberAccessPointer(memberAccess); - - var output = VarName(); - _builder.AppendLine($" {output} {QBEAssign(memberAccess.Type)} {QBELoad(memberAccess.Type)} {pointer}"); - return new Val(output, memberAccess.Type); + + return new Val(output, memberAccess.Type, ValKind.Immediate); } private static Val EmitFixedArrayInitializer(BoundFixedArrayInitializerNode fixedArrayInitializer) @@ -1227,7 +1296,7 @@ public static class QBEGenerator var dataSize = totalSize - 8; _builder.AppendLine($" call $nub_memset(l {dataPtr}, w 0, l {dataSize})"); - return new Val(outputName, fixedArrayInitializer.Type); + return new Val(outputName, fixedArrayInitializer.Type, ValKind.Immediate); } private static Val EmitFuncCall(BoundFuncCallNode funcCall) @@ -1264,6 +1333,7 @@ public static class QBEGenerator NubFixedArrayType => "l", NubFuncType => "l", NubCStringType => "l", + NubStringType => "l", _ => throw new NotSupportedException($"'{parameter.Type}' type cannot be used in function calls") }; parameterStrings.Add($"{qbeType} {result}"); @@ -1275,12 +1345,12 @@ public static class QBEGenerator { var outputName = VarName(); _builder.AppendLine($" {outputName} {QBEAssign(funcCall.Type)} call {funcPointer}({string.Join(", ", parameterStrings)})"); - return new Val(outputName, funcCall.Type); + return new Val(outputName, funcCall.Type, ValKind.Immediate); } else { _builder.AppendLine($" call {funcPointer}({string.Join(", ", parameterStrings)})"); - return new Val(string.Empty, funcCall.Type); + return new Val(string.Empty, funcCall.Type, ValKind.Immediate); } } @@ -1306,9 +1376,9 @@ public static class QBEGenerator switch (val.Kind) { case ValKind.Func: - case ValKind.Literal: + case ValKind.Immediate: return val.Name; - case ValKind.Variable: + case ValKind.Pointer: if (IsPointerType(val.Type)) { return val.Name; @@ -1325,6 +1395,12 @@ public static class QBEGenerator } } +internal class StringLiteral(string value, string name) +{ + public string Value { get; } = value; + public string Name { get; } = name; +} + internal class CStringLiteral(string value, string name) { public string Value { get; } = value; @@ -1337,7 +1413,7 @@ internal class Variable(string name, Val val) public Val Val { get; } = val; } -internal class Val(string name, NubType type, ValKind kind = ValKind.Variable) +internal class Val(string name, NubType type, ValKind kind) { public string Name { get; } = name; public NubType Type { get; } = type; @@ -1352,6 +1428,6 @@ internal class Val(string name, NubType type, ValKind kind = ValKind.Variable) internal enum ValKind { Func, - Variable, - Literal + Pointer, + Immediate } \ No newline at end of file diff --git a/src/Syntax/Parsing/Node/Expression.cs b/src/Syntax/Parsing/Node/Expression.cs index d77e12a..a71316b 100644 --- a/src/Syntax/Parsing/Node/Expression.cs +++ b/src/Syntax/Parsing/Node/Expression.cs @@ -39,6 +39,6 @@ public record AnonymousFuncNode(IEnumerable Tokens, List P public record AddressOfNode(IEnumerable Tokens, LValueNode Expression) : ExpressionNode(Tokens); public record FixedArrayInitializerNode(IEnumerable Tokens, NubType ElementType, int Capacity) : ExpressionNode(Tokens); public record LiteralNode(IEnumerable Tokens, string Literal, LiteralKind Kind) : ExpressionNode(Tokens); -public record MemberAccessNode(IEnumerable Tokens, ExpressionNode Expression, string Member) : LValueNode(Tokens); +public record MemberAccessNode(IEnumerable Tokens, ExpressionNode Expression, string Member) : ExpressionNode(Tokens); public record StructInitializerNode(IEnumerable Tokens, NubStructType StructType, Dictionary Initializers) : ExpressionNode(Tokens); public record DereferenceNode(IEnumerable Tokens, ExpressionNode Expression) : LValueNode(Tokens); diff --git a/src/Syntax/Parsing/Parser.cs b/src/Syntax/Parsing/Parser.cs index 75cf666..546310f 100644 --- a/src/Syntax/Parsing/Parser.cs +++ b/src/Syntax/Parsing/Parser.cs @@ -668,7 +668,7 @@ public static class Parser if (name.Value == "string") { - return new NubArrayType(NubPrimitiveType.U8); + return new NubStringType(); } if (name.Value == "cstring") diff --git a/src/Syntax/Typing/Binder.cs b/src/Syntax/Typing/Binder.cs index a82667b..306d40f 100644 --- a/src/Syntax/Typing/Binder.cs +++ b/src/Syntax/Typing/Binder.cs @@ -347,7 +347,7 @@ public static class Binder { LiteralKind.Integer => NubPrimitiveType.I64, LiteralKind.Float => NubPrimitiveType.F64, - LiteralKind.String => new NubCStringType(), + LiteralKind.String => new NubStringType(), LiteralKind.Bool => NubPrimitiveType.Bool, _ => throw new ArgumentOutOfRangeException() }; @@ -364,10 +364,12 @@ public static class Binder switch (boundExpression.Type) { case NubArrayType: + case NubStringType: + case NubCStringType: { if (expression.Member == "count") { - type = NubPrimitiveType.I64; + type = NubPrimitiveType.U64; } break; diff --git a/src/Syntax/Typing/BoundNode/Expression.cs b/src/Syntax/Typing/BoundNode/Expression.cs index 5a23807..f6f204f 100644 --- a/src/Syntax/Typing/BoundNode/Expression.cs +++ b/src/Syntax/Typing/BoundNode/Expression.cs @@ -16,6 +16,6 @@ public record BoundAnonymousFuncNode(IEnumerable Tokens, NubType Type, Li public record BoundAddressOfNode(IEnumerable Tokens, NubType Type, BoundLValueNode Expression) : BoundExpressionNode(Tokens, Type); public record BoundFixedArrayInitializerNode(IEnumerable Tokens, NubType Type, NubType ElementType, int Capacity) : BoundExpressionNode(Tokens, Type); public record BoundLiteralNode(IEnumerable Tokens, NubType Type, string Literal, LiteralKind Kind) : BoundExpressionNode(Tokens, Type); -public record BoundMemberAccessNode(IEnumerable Tokens, NubType Type, BoundExpressionNode Expression, string Member) : BoundLValueNode(Tokens, Type); +public record BoundMemberAccessNode(IEnumerable Tokens, NubType Type, BoundExpressionNode Expression, string Member) : BoundExpressionNode(Tokens, Type); public record BoundStructInitializerNode(IEnumerable Tokens, NubType Type, NubStructType StructType, Dictionary Initializers) : BoundExpressionNode(Tokens, Type); public record BoundDereferenceNode(IEnumerable Tokens, NubType Type, BoundExpressionNode Expression) : BoundLValueNode(Tokens, Type); diff --git a/src/Syntax/Typing/NubType.cs b/src/Syntax/Typing/NubType.cs index fd1ea4c..1c89f69 100644 --- a/src/Syntax/Typing/NubType.cs +++ b/src/Syntax/Typing/NubType.cs @@ -4,21 +4,6 @@ namespace Syntax.Typing; public abstract class NubType { - public static bool IsCompatibleWith(NubType sourceType, NubType targetType) - { - if (targetType is NubAnyType || sourceType.Equals(targetType)) - { - return true; - } - - if (sourceType is NubFixedArrayType fixedArray && targetType is NubArrayType array && IsCompatibleWith(fixedArray.ElementType, array.ElementType)) - { - return true; - } - - return false; - } - public bool IsInteger => this is NubPrimitiveType { Kind: PrimitiveTypeKind.I8 @@ -45,6 +30,15 @@ public abstract class NubType public bool IsVoid => this is NubVoidType; + public bool IsString => this is NubStringType; + + public bool IsCString => this is NubCStringType; + + public bool IsBool => this is NubPrimitiveType + { + Kind: PrimitiveTypeKind.Bool + }; + public abstract override bool Equals(object? obj); public abstract override int GetHashCode(); public abstract override string ToString(); @@ -54,7 +48,7 @@ public class NubCStringType : NubType { public override bool Equals(object? obj) { - return obj is NubCStringType other; + return obj is NubCStringType; } public override int GetHashCode() @@ -68,6 +62,24 @@ public class NubCStringType : NubType } } +public class NubStringType : NubType +{ + public override bool Equals(object? obj) + { + return obj is NubStringType; + } + + public override int GetHashCode() + { + return "string".GetHashCode(); + } + + public override string ToString() + { + return "string"; + } +} + public class NubFuncType(NubType returnType, List parameters) : NubType { public NubType ReturnType { get; } = returnType;