This commit is contained in:
nub31
2025-06-02 19:56:38 +02:00
parent 81fe75446d
commit e874b8e155
7 changed files with 110 additions and 50 deletions

View File

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

3
run.sh
View File

@@ -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 $?"'

View File

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

View File

@@ -3,8 +3,8 @@ using Nub.Lang.Frontend.Typing;
namespace Nub.Lang.Frontend.Parsing.Expressions;
public class ArrayInitializerNode(IReadOnlyList<Token> tokens, ExpressionNode capacity, NubType itemType) : ExpressionNode(tokens)
public class ArrayInitializerNode(IReadOnlyList<Token> tokens, ExpressionNode capacity, NubType elementType) : ExpressionNode(tokens)
{
public ExpressionNode Capacity { get; } = capacity;
public NubType ItemType { get; } = itemType;
public NubType ElementType { get; } = elementType;
}

View File

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

View File

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

View File

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