From ae9a7461c22090bfe071c707ad513801efbb3fab Mon Sep 17 00:00:00 2001 From: nub31 Date: Mon, 2 Jun 2025 19:56:38 +0200 Subject: [PATCH] fuck me --- example/main.nub | 8 +- run.sh | 3 +- .../Nub.Lang/Frontend/Generation/Generator.cs | 125 +++++++++++++----- .../Expressions/ArrayInitializerNode.cs | 4 +- src/lang/Nub.Lang/Frontend/Parsing/Parser.cs | 5 +- src/lang/Nub.Lang/Frontend/Typing/NubType.cs | 6 +- .../Nub.Lang/Frontend/Typing/TypeChecker.cs | 9 +- 7 files changed, 110 insertions(+), 50 deletions(-) diff --git a/example/main.nub b/example/main.nub index 2918c53..38296d7 100644 --- a/example/main.nub +++ b/example/main.nub @@ -6,8 +6,12 @@ struct Human { } export func main(args: []^string) { - let human = alloc Human { - age = 23 + let human = [1]Human + + human[0] = alloc Human { name = "oliver" + age = 123 } + + c::printf("%s\n", human[1].name) } \ No newline at end of file diff --git a/run.sh b/run.sh index ea586ab..2572e63 100755 --- a/run.sh +++ b/run.sh @@ -2,5 +2,4 @@ set -e ./clean.sh ./build.sh -./out/program -echo "Process exited with status code $?" +bash -c './out/program; echo "Process exited with status code $?"' diff --git a/src/lang/Nub.Lang/Frontend/Generation/Generator.cs b/src/lang/Nub.Lang/Frontend/Generation/Generator.cs index 976a545..474e559 100644 --- a/src/lang/Nub.Lang/Frontend/Generation/Generator.cs +++ b/src/lang/Nub.Lang/Frontend/Generation/Generator.cs @@ -275,7 +275,14 @@ public class Generator private bool IsLargeType(NubType type) { - return QbeTypeSize(type) > 8; + return type switch + { + NubArrayType => false, + NubPointerType => false, + NubPrimitiveType => false, + NubStructType => true, + _ => throw new ArgumentOutOfRangeException(nameof(type)) + }; } private void GenerateFuncDefinition(LocalFuncDefinitionNode node) @@ -333,7 +340,6 @@ public class Generator _builder.AppendLine($" %{pointerName} ={SQT(parameter.Type)} alloc8 {QbeTypeSize(parameter.Type)}"); _builder.AppendLine($" storel %{parameterName}, %{pointerName}"); - _variables[parameter.Name] = new Variable { Pointer = $"%{pointerName}", @@ -373,7 +379,7 @@ public class Generator switch (statement) { case ArrayIndexAssignmentNode arrayIndexAssignment: - throw new NotImplementedException(); + GenerateArrayIndexAssignment(arrayIndexAssignment); break; case BreakNode: GenerateBreak(); @@ -407,6 +413,36 @@ public class Generator } } + private void GenerateArrayIndexAssignment(ArrayIndexAssignmentNode arrayIndexAssignment) + { + var arrayType = (NubArrayType)arrayIndexAssignment.ArrayIndexAccess.Array.Type; + + var array = GenerateExpression(arrayIndexAssignment.ArrayIndexAccess.Array); + var index = GenerateExpression(arrayIndexAssignment.ArrayIndexAccess.Index); + + GenerateArrayBoundsCheck(array, index); + + var value = GenerateExpression(arrayIndexAssignment.Value); + + var startName = GenVarName(); + _builder.AppendLine($" %{startName} =l add {array}, 8"); + + var adjustedIndex = GenVarName(); + _builder.AppendLine($" %{adjustedIndex} =l mul {index}, {QbeTypeSize(arrayType.BaseType)}"); + + var offsetName = GenVarName(); + _builder.AppendLine($" %{offsetName} =l add %{startName}, %{adjustedIndex}"); + + if (IsLargeType(arrayType.BaseType)) + { + _builder.AppendLine($" blit {value}, %{offsetName}, {QbeTypeSize(arrayType.BaseType)}"); + } + else + { + _builder.AppendLine($" store{SQT(arrayType.BaseType)} {value}, %{offsetName}"); + } + } + private void GenerateBlock(BlockNode block) { foreach (var statement in block.Statements.Where(_ => _codeIsReachable)) @@ -558,51 +594,61 @@ public class Generator private string GenerateArrayIndex(ArrayIndexAccessNode arrayIndexAccess) { + var arrayType = ((NubArrayType)arrayIndexAccess.Array.Type).BaseType; + var array = GenerateExpression(arrayIndexAccess.Array); var index = GenerateExpression(arrayIndexAccess.Index); + + GenerateArrayBoundsCheck(array, index); - var arrayBaseType = ((NubArrayType)arrayIndexAccess.Array.Type).BaseType; - - var countName = GenVarName(); - _builder.AppendLine($" %{countName} =l loadl {array}"); - - var isNegativeName = GenVarName(); - _builder.AppendLine($" %{isNegativeName} =w csltl {index}, 0"); - - var isOobName = GenVarName(); - _builder.AppendLine($" %{isOobName} =w csgel {index}, %{countName}"); - - var anyOobName = GenVarName(); - _builder.AppendLine($" %{anyOobName} =w or %{isNegativeName}, %{isOobName}"); - - var oobLabel = GenLabelName(); - var notOobLabel = GenLabelName(); - _builder.AppendLine($" jnz %{anyOobName}, @{oobLabel}, @{notOobLabel}"); - - _builder.AppendLine($"@{oobLabel}"); - _builder.AppendLine($" call $nub_panic(l $oob_message, l {OutOfBoundsMessage.Length})"); - - _builder.AppendLine($"@{notOobLabel}"); - - // Calculate element address var firstItemPointerName = GenVarName(); _builder.AppendLine($" %{firstItemPointerName} =l add {array}, 8"); var offsetPointerName = GenVarName(); - _builder.AppendLine($" %{offsetPointerName} =l mul {index}, {QbeTypeSize(arrayBaseType)}"); + _builder.AppendLine($" %{offsetPointerName} =l mul {index}, {QbeTypeSize(arrayType)}"); var resultPointerName = GenVarName(); _builder.AppendLine($" %{resultPointerName} =l add %{firstItemPointerName}, %{offsetPointerName}"); - // Load the value - var outputName = GenVarName(); - _builder.AppendLine($" %{outputName} ={SQT(arrayBaseType)} load{SQT(arrayBaseType)} %{resultPointerName}"); - return $"%{outputName}"; + if (IsLargeType(arrayType)) + { + return $"%{resultPointerName}"; + } + else + { + var outputName = GenVarName(); + _builder.AppendLine($" %{outputName} ={SQT(arrayType)} load{SQT(arrayType)} %{resultPointerName}"); + return $"%{outputName}"; + } + } + + private void GenerateArrayBoundsCheck(string array, string index) + { + var countName = GenVarName(); + _builder.AppendLine($" %{countName} =l loadl {array}"); + + var isNegativeName = GenVarName(); + _builder.AppendLine($" %{isNegativeName} =w csltl {index}, 0"); + + var isOobName = GenVarName(); + _builder.AppendLine($" %{isOobName} =w csgel {index}, %{countName}"); + + var anyOobName = GenVarName(); + _builder.AppendLine($" %{anyOobName} =w or %{isNegativeName}, %{isOobName}"); + + var oobLabel = GenLabelName(); + var notOobLabel = GenLabelName(); + _builder.AppendLine($" jnz %{anyOobName}, @{oobLabel}, @{notOobLabel}"); + + _builder.AppendLine($"@{oobLabel}"); + _builder.AppendLine($" call $nub_panic(l $oob_message, l {OutOfBoundsMessage.Length})"); + + _builder.AppendLine($"@{notOobLabel}"); } private string GenerateArrayInitializer(ArrayInitializerNode arrayInitializer) { var capacity = GenerateExpression(arrayInitializer.Capacity); var capacityInBytes = GenVarName(); - _builder.AppendLine($" %{capacityInBytes} =l mul {capacity}, {QbeTypeSize(arrayInitializer.ItemType)}"); + _builder.AppendLine($" %{capacityInBytes} =l mul {capacity}, {QbeTypeSize(arrayInitializer.ElementType)}"); var totalArraySize = GenVarName(); _builder.AppendLine($" %{totalArraySize} =l add %{capacityInBytes}, 8"); var outputName = GenVarName(); @@ -1326,9 +1372,16 @@ public class Generator private string GenerateIdentifier(IdentifierNode identifier) { var variable = _variables[identifier.Identifier]; - var outputName = GenVarName(); - _builder.AppendLine($" %{outputName} ={SQT(identifier.Type)} load{SQT(identifier.Type)} {variable.Pointer}"); - return $"%{outputName}"; + if (IsLargeType(identifier.Type)) + { + return variable.Pointer; + } + else + { + var outputName = GenVarName(); + _builder.AppendLine($" %{outputName} ={SQT(identifier.Type)} load{SQT(identifier.Type)} {variable.Pointer}"); + return $"%{outputName}"; + } } private string GenerateLiteral(LiteralNode literal) diff --git a/src/lang/Nub.Lang/Frontend/Parsing/Expressions/ArrayInitializerNode.cs b/src/lang/Nub.Lang/Frontend/Parsing/Expressions/ArrayInitializerNode.cs index c6b8aae..6b92ba4 100644 --- a/src/lang/Nub.Lang/Frontend/Parsing/Expressions/ArrayInitializerNode.cs +++ b/src/lang/Nub.Lang/Frontend/Parsing/Expressions/ArrayInitializerNode.cs @@ -3,8 +3,8 @@ using Nub.Lang.Frontend.Typing; namespace Nub.Lang.Frontend.Parsing.Expressions; -public class ArrayInitializerNode(IReadOnlyList tokens, ExpressionNode capacity, NubType itemType) : ExpressionNode(tokens) +public class ArrayInitializerNode(IReadOnlyList tokens, ExpressionNode capacity, NubType elementType) : ExpressionNode(tokens) { public ExpressionNode Capacity { get; } = capacity; - public NubType ItemType { get; } = itemType; + public NubType ElementType { get; } = elementType; } \ No newline at end of file diff --git a/src/lang/Nub.Lang/Frontend/Parsing/Parser.cs b/src/lang/Nub.Lang/Frontend/Parsing/Parser.cs index 2b1d7fa..a3698b0 100644 --- a/src/lang/Nub.Lang/Frontend/Parsing/Parser.cs +++ b/src/lang/Nub.Lang/Frontend/Parsing/Parser.cs @@ -513,10 +513,11 @@ public class Parser } case Symbol.OpenBracket: { - var size = ParseExpression(); + var capacity = ParseExpression(); ExpectSymbol(Symbol.CloseBracket); var type = ParseType(); - expr = new ArrayInitializerNode(GetTokensForNode(startIndex), size, type); + + expr = new ArrayInitializerNode(GetTokensForNode(startIndex), capacity, type); break; } case Symbol.Alloc: diff --git a/src/lang/Nub.Lang/Frontend/Typing/NubType.cs b/src/lang/Nub.Lang/Frontend/Typing/NubType.cs index f3e04dd..3f6b7fa 100644 --- a/src/lang/Nub.Lang/Frontend/Typing/NubType.cs +++ b/src/lang/Nub.Lang/Frontend/Typing/NubType.cs @@ -58,7 +58,7 @@ public class NubPointerType(NubType baseType) : NubType public class NubArrayType(NubType baseType) : NubType { public NubType BaseType { get; } = baseType; - + public override bool Equals(object? obj) { if (obj is NubArrayType other) @@ -135,7 +135,7 @@ public class NubPrimitiveType(PrimitiveTypeKind kind) : NubType public override string ToString() { - return kind switch + return Kind switch { PrimitiveTypeKind.I8 => "i8", PrimitiveTypeKind.I16 => "i16", @@ -153,7 +153,7 @@ public class NubPrimitiveType(PrimitiveTypeKind kind) : NubType PrimitiveTypeKind.Bool => "bool", PrimitiveTypeKind.String => "string", PrimitiveTypeKind.Any => "any", - _ => throw new ArgumentOutOfRangeException(nameof(kind), kind, null) + _ => throw new ArgumentOutOfRangeException(nameof(kind), Kind, null) }; } } diff --git a/src/lang/Nub.Lang/Frontend/Typing/TypeChecker.cs b/src/lang/Nub.Lang/Frontend/Typing/TypeChecker.cs index 6d42086..9a3753e 100644 --- a/src/lang/Nub.Lang/Frontend/Typing/TypeChecker.cs +++ b/src/lang/Nub.Lang/Frontend/Typing/TypeChecker.cs @@ -183,7 +183,8 @@ public class TypeChecker if (!NubType.IsCompatibleWith(variableAssignment.Value.Type, existingVariable)) { - ReportError($"Cannot assign expression of type '{variableAssignment.Value.Type}' to variable '{variableAssignment.Identifier}' with type '{existingVariable}'", variableAssignment); + ReportError($"Cannot assign expression of type '{variableAssignment.Value.Type}' to variable '{variableAssignment.Identifier}' with type '{existingVariable}'", + variableAssignment); } } @@ -212,7 +213,9 @@ public class TypeChecker { if (!NubType.IsCompatibleWith(variableDeclaration.ExplicitType.Value, variableDeclaration.Value.Value.Type)) { - ReportError($"Cannot assign expression of type '{variableDeclaration.Value.Value.Type}' to variable '{variableDeclaration.Name}' with type '{variableDeclaration.ExplicitType.Value}'", variableDeclaration); + ReportError( + $"Cannot assign expression of type '{variableDeclaration.Value.Value.Type}' to variable '{variableDeclaration.Name}' with type '{variableDeclaration.ExplicitType.Value}'", + variableDeclaration); } } @@ -405,7 +408,7 @@ public class TypeChecker ReportError("Array capacity type must be an integer", arrayInitializer.Capacity); } - return new NubArrayType(arrayInitializer.ItemType); + return new NubArrayType(arrayInitializer.ElementType); } private NubType? TypeCheckIdentifier(IdentifierNode identifier)