From 4f89e55bec03fa9aa29f012bda42ba61f36e9830 Mon Sep 17 00:00:00 2001 From: nub31 Date: Tue, 27 May 2025 15:07:55 +0200 Subject: [PATCH] Array init support --- example/math/math.nub | 5 -- example/program.nub | 14 ++-- src/lang/Nub.Lang/Backend/Generator.cs | 19 ++++++ src/lang/Nub.Lang/Frontend/Lexing/Lexer.cs | 67 +++++++------------ .../Frontend/Parsing/ArrayInitializerNode.cs | 10 +++ src/lang/Nub.Lang/Frontend/Parsing/Parser.cs | 50 +++++++------- src/lang/Nub.Lang/Frontend/Typing/NubType.cs | 2 +- .../Nub.Lang/Frontend/Typing/TypeChecker.cs | 12 ++++ 8 files changed, 101 insertions(+), 78 deletions(-) delete mode 100644 example/math/math.nub create mode 100644 src/lang/Nub.Lang/Frontend/Parsing/ArrayInitializerNode.cs diff --git a/example/math/math.nub b/example/math/math.nub deleted file mode 100644 index 267b678..0000000 --- a/example/math/math.nub +++ /dev/null @@ -1,5 +0,0 @@ -namespace math - -func add(a: i64, b: i64): i64 { - return a + b -} \ No newline at end of file diff --git a/example/program.nub b/example/program.nub index 60b0d1d..c64628e 100644 --- a/example/program.nub +++ b/example/program.nub @@ -3,15 +3,15 @@ namespace main /// # Documentation /// ## Documentation subtitle export func main(args: []string) { - let i: i64 + // let i: i64 - let x = math::add(1, 1) + // c::printf("%d\n", args.count) - c::printf("%d\n", args.count) + // while i < args.count { + // c::printf("%s\n", args[i]) - while i < args.count { - c::printf("%s\n", args[i]) + // i = i + 1 + // } - i = i + 1 - } + let arr = new [10]i64 } \ No newline at end of file diff --git a/src/lang/Nub.Lang/Backend/Generator.cs b/src/lang/Nub.Lang/Backend/Generator.cs index d1871f4..bbdca5d 100644 --- a/src/lang/Nub.Lang/Backend/Generator.cs +++ b/src/lang/Nub.Lang/Backend/Generator.cs @@ -558,6 +558,7 @@ public class Generator { AddressOfNode addressOf => GenerateAddressOf(addressOf), ArrayIndexNode arrayIndex => GenerateArrayIndex(arrayIndex), + ArrayInitializerNode arrayInitializer => GenerateArrayInitializer(arrayInitializer), BinaryExpressionNode binaryExpression => GenerateBinaryExpression(binaryExpression), CastNode cast => GenerateCast(cast), DereferenceNode dereference => GenerateDereference(dereference), @@ -589,6 +590,24 @@ public class Generator return $"%{outputName}"; } + private string GenerateArrayInitializer(ArrayInitializerNode arrayInitializer) + { + var capacity = GenerateExpression(arrayInitializer.Capacity); + var capacityInBytes = GenVarName(); + _builder.AppendLine($" %{capacityInBytes} =l mul {capacity}, {QbeTypeSize(arrayInitializer.ItemType)}"); + var totalArraySize = GenVarName(); + _builder.AppendLine($" %{totalArraySize} =l add %{capacityInBytes}, 8"); + var outputName = GenVarName(); + _builder.AppendLine($" %{outputName} =l alloc8 %{totalArraySize}"); + _builder.AppendLine($" storel {capacity}, %{outputName}"); + + var dataPtr = GenVarName(); + _builder.AppendLine($" %{dataPtr} =l add %{outputName}, 8"); + _builder.AppendLine($" call $nub_memset(l %{dataPtr}, w 0, l %{capacityInBytes})"); + + return $"%{outputName}"; + } + private string GenerateDereference(DereferenceNode dereference) { var result = GenerateExpression(dereference.Expression); diff --git a/src/lang/Nub.Lang/Frontend/Lexing/Lexer.cs b/src/lang/Nub.Lang/Frontend/Lexing/Lexer.cs index 1cd21ae..40bdf03 100644 --- a/src/lang/Nub.Lang/Frontend/Lexing/Lexer.cs +++ b/src/lang/Nub.Lang/Frontend/Lexing/Lexer.cs @@ -89,52 +89,37 @@ public class Lexer ConsumeWhitespace(); var startIndex = _index; - string? documentation = null; - while (Peek() is { Value: '/' } && Peek(1) is { Value: '/' }) - { - Next(); - Next(); - - if (Peek() is { Value: '/' }) - { - Next(); - - while (Peek().TryGetValue(out var character)) - { - Next(); - documentation += character; - if (character == '\n') - { - break; - } - } - } - else - { - while (Peek().TryGetValue(out var character)) - { - Next(); - if (character == '\n') - { - break; - } - } - } - } - - if (documentation != null) - { - return new DocumentationToken(_sourceText, startIndex, _index, documentation); - } - - ConsumeWhitespace(); - startIndex = _index; - if (!Peek().TryGetValue(out var current)) { return Optional.Empty(); } + if (current == '/' && Peek(1).TryGetValue(out var nextChar) && nextChar == '/') + { + Next(); + Next(); + + if (Peek().TryGetValue(out var thirdChar) && thirdChar == '/') + { + Next(); + var buffer = string.Empty; + while (Peek().TryGetValue(out var character) && character != '\n') + { + buffer += character; + Next(); + } + Next(); + return new DocumentationToken(_sourceText, startIndex, _index, buffer); + } + + while (Peek().TryGetValue(out var character) && character != '\n') + { + Next(); + } + Next(); + return ParseToken(); + } + if (char.IsLetter(current) || current == '_') { var buffer = string.Empty; diff --git a/src/lang/Nub.Lang/Frontend/Parsing/ArrayInitializerNode.cs b/src/lang/Nub.Lang/Frontend/Parsing/ArrayInitializerNode.cs new file mode 100644 index 0000000..b0d5c13 --- /dev/null +++ b/src/lang/Nub.Lang/Frontend/Parsing/ArrayInitializerNode.cs @@ -0,0 +1,10 @@ +using Nub.Lang.Frontend.Lexing; +using Nub.Lang.Frontend.Typing; + +namespace Nub.Lang.Frontend.Parsing; + +public class ArrayInitializerNode(IReadOnlyList tokens, ExpressionNode capacity, NubType itemType) : ExpressionNode(tokens) +{ + public ExpressionNode Capacity { get; } = capacity; + public NubType ItemType { get; } = itemType; +} \ 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 e5ea791..cc6e4e9 100644 --- a/src/lang/Nub.Lang/Frontend/Parsing/Parser.cs +++ b/src/lang/Nub.Lang/Frontend/Parsing/Parser.cs @@ -498,37 +498,39 @@ public class Parser } case Symbol.New: { - var type = ParseType(); - switch (type) + var next = Peek(); + if (next.Value is SymbolToken { Symbol: Symbol.OpenBracket }) { - case NubStructType structType: + Next(); + var size = ParseExpression(); + ExpectSymbol(Symbol.CloseBracket); + var type = ParseType(); + expr = new ArrayInitializerNode(GetTokensForNode(startIndex), size, type); + } + else + { + var type = ParseType(); + Dictionary initializers = []; + ExpectSymbol(Symbol.OpenBrace); + while (!TryExpectSymbol(Symbol.CloseBrace)) { - Dictionary initializers = []; - ExpectSymbol(Symbol.OpenBrace); - while (!TryExpectSymbol(Symbol.CloseBrace)) - { - var name = ExpectIdentifier().Value; - ExpectSymbol(Symbol.Assign); - var value = ParseExpression(); - initializers.Add(name, value); - } + var name = ExpectIdentifier().Value; + ExpectSymbol(Symbol.Assign); + var value = ParseExpression(); + initializers.Add(name, value); + } - expr = new StructInitializerNode(GetTokensForNode(startIndex), structType, initializers); - break; - } - case NubArrayType arrayType: - { - throw new NotImplementedException(); - } - default: + if (type is not NubStructType structType) { throw new ParseException(Diagnostic - .Error($"Cannot use new keyword on type {type}") - .At(symbolToken) - .Build()); + .Error($"Cannot use new keyword on type {type}") + .At(symbolToken) + .Build()); } + + expr = new StructInitializerNode(GetTokensForNode(startIndex), structType, initializers); } - + break; } case Symbol.Ampersand: diff --git a/src/lang/Nub.Lang/Frontend/Typing/NubType.cs b/src/lang/Nub.Lang/Frontend/Typing/NubType.cs index b65bf7a..a9a1943 100644 --- a/src/lang/Nub.Lang/Frontend/Typing/NubType.cs +++ b/src/lang/Nub.Lang/Frontend/Typing/NubType.cs @@ -21,7 +21,7 @@ public abstract class NubType public override string ToString() => Name; } -public class NubStructType(string name, string @namespace) : NubType(name) +public class NubStructType(string @namespace, string name) : NubType(name) { public string Namespace { get; } = @namespace; } diff --git a/src/lang/Nub.Lang/Frontend/Typing/TypeChecker.cs b/src/lang/Nub.Lang/Frontend/Typing/TypeChecker.cs index 7593545..b8e75b5 100644 --- a/src/lang/Nub.Lang/Frontend/Typing/TypeChecker.cs +++ b/src/lang/Nub.Lang/Frontend/Typing/TypeChecker.cs @@ -315,6 +315,7 @@ public class TypeChecker { AddressOfNode addressOf => TypeCheckAddressOf(addressOf), ArrayIndexNode arrayIndex => TypeCheckArrayIndex(arrayIndex), + ArrayInitializerNode arrayInitializer => TypeCheckArrayInitializer(arrayInitializer), LiteralNode literal => literal.LiteralType, IdentifierNode identifier => TypeCheckIdentifier(identifier), BinaryExpressionNode binaryExpr => TypeCheckBinaryExpression(binaryExpr), @@ -361,6 +362,17 @@ public class TypeChecker return arrayType.BaseType; } + private NubType TypeCheckArrayInitializer(ArrayInitializerNode arrayInitializer) + { + var capacityType = TypeCheckExpression(arrayInitializer.Capacity); + if (capacityType != null && !IsInteger(capacityType)) + { + ReportError("Array capacity type must be an integer", arrayInitializer.Capacity); + } + + return new NubArrayType(arrayInitializer.ItemType); + } + private NubType? TypeCheckIdentifier(IdentifierNode identifier) { if (!_variables.TryGetValue(identifier.Identifier, out var varType))