Array init support

This commit is contained in:
nub31
2025-05-27 15:07:55 +02:00
parent db231cc553
commit 5ea611b6d5
8 changed files with 101 additions and 78 deletions

View File

@@ -1,5 +0,0 @@
namespace math
func add(a: i64, b: i64): i64 {
return a + b
}

View File

@@ -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
}

View File

@@ -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);

View File

@@ -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<Token>.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;

View File

@@ -0,0 +1,10 @@
using Nub.Lang.Frontend.Lexing;
using Nub.Lang.Frontend.Typing;
namespace Nub.Lang.Frontend.Parsing;
public class ArrayInitializerNode(IReadOnlyList<Token> tokens, ExpressionNode capacity, NubType itemType) : ExpressionNode(tokens)
{
public ExpressionNode Capacity { get; } = capacity;
public NubType ItemType { get; } = itemType;
}

View File

@@ -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<string, ExpressionNode> initializers = [];
ExpectSymbol(Symbol.OpenBrace);
while (!TryExpectSymbol(Symbol.CloseBrace))
{
Dictionary<string, ExpressionNode> 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:

View File

@@ -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;
}

View File

@@ -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))