Array init support

This commit is contained in:
nub31
2025-05-27 15:07:55 +02:00
parent 3d3a5414d7
commit 4f89e55bec
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
/// ## Documentation subtitle /// ## Documentation subtitle
export func main(args: []string) { 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 { // i = i + 1
c::printf("%s\n", args[i]) // }
i = i + 1 let arr = new [10]i64
}
} }

View File

@@ -558,6 +558,7 @@ public class Generator
{ {
AddressOfNode addressOf => GenerateAddressOf(addressOf), AddressOfNode addressOf => GenerateAddressOf(addressOf),
ArrayIndexNode arrayIndex => GenerateArrayIndex(arrayIndex), ArrayIndexNode arrayIndex => GenerateArrayIndex(arrayIndex),
ArrayInitializerNode arrayInitializer => GenerateArrayInitializer(arrayInitializer),
BinaryExpressionNode binaryExpression => GenerateBinaryExpression(binaryExpression), BinaryExpressionNode binaryExpression => GenerateBinaryExpression(binaryExpression),
CastNode cast => GenerateCast(cast), CastNode cast => GenerateCast(cast),
DereferenceNode dereference => GenerateDereference(dereference), DereferenceNode dereference => GenerateDereference(dereference),
@@ -589,6 +590,24 @@ public class Generator
return $"%{outputName}"; 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) private string GenerateDereference(DereferenceNode dereference)
{ {
var result = GenerateExpression(dereference.Expression); var result = GenerateExpression(dereference.Expression);

View File

@@ -89,52 +89,37 @@ public class Lexer
ConsumeWhitespace(); ConsumeWhitespace();
var startIndex = _index; 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)) if (!Peek().TryGetValue(out var current))
{ {
return Optional<Token>.Empty(); 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 == '_') if (char.IsLetter(current) || current == '_')
{ {
var buffer = string.Empty; 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: case Symbol.New:
{ {
var type = ParseType(); var next = Peek();
switch (type) 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 = []; var name = ExpectIdentifier().Value;
ExpectSymbol(Symbol.OpenBrace); ExpectSymbol(Symbol.Assign);
while (!TryExpectSymbol(Symbol.CloseBrace)) 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); if (type is not NubStructType structType)
break;
}
case NubArrayType arrayType:
{
throw new NotImplementedException();
}
default:
{ {
throw new ParseException(Diagnostic throw new ParseException(Diagnostic
.Error($"Cannot use new keyword on type {type}") .Error($"Cannot use new keyword on type {type}")
.At(symbolToken) .At(symbolToken)
.Build()); .Build());
} }
expr = new StructInitializerNode(GetTokensForNode(startIndex), structType, initializers);
} }
break; break;
} }
case Symbol.Ampersand: case Symbol.Ampersand:

View File

@@ -21,7 +21,7 @@ public abstract class NubType
public override string ToString() => Name; 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; public string Namespace { get; } = @namespace;
} }

View File

@@ -315,6 +315,7 @@ public class TypeChecker
{ {
AddressOfNode addressOf => TypeCheckAddressOf(addressOf), AddressOfNode addressOf => TypeCheckAddressOf(addressOf),
ArrayIndexNode arrayIndex => TypeCheckArrayIndex(arrayIndex), ArrayIndexNode arrayIndex => TypeCheckArrayIndex(arrayIndex),
ArrayInitializerNode arrayInitializer => TypeCheckArrayInitializer(arrayInitializer),
LiteralNode literal => literal.LiteralType, LiteralNode literal => literal.LiteralType,
IdentifierNode identifier => TypeCheckIdentifier(identifier), IdentifierNode identifier => TypeCheckIdentifier(identifier),
BinaryExpressionNode binaryExpr => TypeCheckBinaryExpression(binaryExpr), BinaryExpressionNode binaryExpr => TypeCheckBinaryExpression(binaryExpr),
@@ -361,6 +362,17 @@ public class TypeChecker
return arrayType.BaseType; 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) private NubType? TypeCheckIdentifier(IdentifierNode identifier)
{ {
if (!_variables.TryGetValue(identifier.Identifier, out var varType)) if (!_variables.TryGetValue(identifier.Identifier, out var varType))