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

View File

@@ -6,8 +6,12 @@ struct Human {
} }
export func main(args: []^string) { export func main(args: []^string) {
let human = alloc Human { let human = [1]Human
age = 23
human[0] = alloc Human {
name = "oliver" name = "oliver"
age = 123
} }
c::printf("%s\n", human[1].name)
} }

3
run.sh
View File

@@ -2,5 +2,4 @@
set -e set -e
./clean.sh ./clean.sh
./build.sh ./build.sh
./out/program bash -c './out/program; echo "Process exited with status code $?"'
echo "Process exited with status code $?"

View File

@@ -275,7 +275,14 @@ public class Generator
private bool IsLargeType(NubType type) 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) private void GenerateFuncDefinition(LocalFuncDefinitionNode node)
@@ -333,7 +340,6 @@ public class Generator
_builder.AppendLine($" %{pointerName} ={SQT(parameter.Type)} alloc8 {QbeTypeSize(parameter.Type)}"); _builder.AppendLine($" %{pointerName} ={SQT(parameter.Type)} alloc8 {QbeTypeSize(parameter.Type)}");
_builder.AppendLine($" storel %{parameterName}, %{pointerName}"); _builder.AppendLine($" storel %{parameterName}, %{pointerName}");
_variables[parameter.Name] = new Variable _variables[parameter.Name] = new Variable
{ {
Pointer = $"%{pointerName}", Pointer = $"%{pointerName}",
@@ -373,7 +379,7 @@ public class Generator
switch (statement) switch (statement)
{ {
case ArrayIndexAssignmentNode arrayIndexAssignment: case ArrayIndexAssignmentNode arrayIndexAssignment:
throw new NotImplementedException(); GenerateArrayIndexAssignment(arrayIndexAssignment);
break; break;
case BreakNode: case BreakNode:
GenerateBreak(); 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) private void GenerateBlock(BlockNode block)
{ {
foreach (var statement in block.Statements.Where(_ => _codeIsReachable)) foreach (var statement in block.Statements.Where(_ => _codeIsReachable))
@@ -558,51 +594,61 @@ public class Generator
private string GenerateArrayIndex(ArrayIndexAccessNode arrayIndexAccess) private string GenerateArrayIndex(ArrayIndexAccessNode arrayIndexAccess)
{ {
var arrayType = ((NubArrayType)arrayIndexAccess.Array.Type).BaseType;
var array = GenerateExpression(arrayIndexAccess.Array); var array = GenerateExpression(arrayIndexAccess.Array);
var index = GenerateExpression(arrayIndexAccess.Index); 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(); var firstItemPointerName = GenVarName();
_builder.AppendLine($" %{firstItemPointerName} =l add {array}, 8"); _builder.AppendLine($" %{firstItemPointerName} =l add {array}, 8");
var offsetPointerName = GenVarName(); var offsetPointerName = GenVarName();
_builder.AppendLine($" %{offsetPointerName} =l mul {index}, {QbeTypeSize(arrayBaseType)}"); _builder.AppendLine($" %{offsetPointerName} =l mul {index}, {QbeTypeSize(arrayType)}");
var resultPointerName = GenVarName(); var resultPointerName = GenVarName();
_builder.AppendLine($" %{resultPointerName} =l add %{firstItemPointerName}, %{offsetPointerName}"); _builder.AppendLine($" %{resultPointerName} =l add %{firstItemPointerName}, %{offsetPointerName}");
// Load the value if (IsLargeType(arrayType))
var outputName = GenVarName(); {
_builder.AppendLine($" %{outputName} ={SQT(arrayBaseType)} load{SQT(arrayBaseType)} %{resultPointerName}"); return $"%{resultPointerName}";
return $"%{outputName}"; }
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) private string GenerateArrayInitializer(ArrayInitializerNode arrayInitializer)
{ {
var capacity = GenerateExpression(arrayInitializer.Capacity); var capacity = GenerateExpression(arrayInitializer.Capacity);
var capacityInBytes = GenVarName(); var capacityInBytes = GenVarName();
_builder.AppendLine($" %{capacityInBytes} =l mul {capacity}, {QbeTypeSize(arrayInitializer.ItemType)}"); _builder.AppendLine($" %{capacityInBytes} =l mul {capacity}, {QbeTypeSize(arrayInitializer.ElementType)}");
var totalArraySize = GenVarName(); var totalArraySize = GenVarName();
_builder.AppendLine($" %{totalArraySize} =l add %{capacityInBytes}, 8"); _builder.AppendLine($" %{totalArraySize} =l add %{capacityInBytes}, 8");
var outputName = GenVarName(); var outputName = GenVarName();
@@ -1326,9 +1372,16 @@ public class Generator
private string GenerateIdentifier(IdentifierNode identifier) private string GenerateIdentifier(IdentifierNode identifier)
{ {
var variable = _variables[identifier.Identifier]; var variable = _variables[identifier.Identifier];
var outputName = GenVarName(); if (IsLargeType(identifier.Type))
_builder.AppendLine($" %{outputName} ={SQT(identifier.Type)} load{SQT(identifier.Type)} {variable.Pointer}"); {
return $"%{outputName}"; 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) private string GenerateLiteral(LiteralNode literal)

View File

@@ -3,8 +3,8 @@ using Nub.Lang.Frontend.Typing;
namespace Nub.Lang.Frontend.Parsing.Expressions; 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 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: case Symbol.OpenBracket:
{ {
var size = ParseExpression(); var capacity = ParseExpression();
ExpectSymbol(Symbol.CloseBracket); ExpectSymbol(Symbol.CloseBracket);
var type = ParseType(); var type = ParseType();
expr = new ArrayInitializerNode(GetTokensForNode(startIndex), size, type);
expr = new ArrayInitializerNode(GetTokensForNode(startIndex), capacity, type);
break; break;
} }
case Symbol.Alloc: case Symbol.Alloc:

View File

@@ -58,7 +58,7 @@ public class NubPointerType(NubType baseType) : NubType
public class NubArrayType(NubType baseType) : NubType public class NubArrayType(NubType baseType) : NubType
{ {
public NubType BaseType { get; } = baseType; public NubType BaseType { get; } = baseType;
public override bool Equals(object? obj) public override bool Equals(object? obj)
{ {
if (obj is NubArrayType other) if (obj is NubArrayType other)
@@ -135,7 +135,7 @@ public class NubPrimitiveType(PrimitiveTypeKind kind) : NubType
public override string ToString() public override string ToString()
{ {
return kind switch return Kind switch
{ {
PrimitiveTypeKind.I8 => "i8", PrimitiveTypeKind.I8 => "i8",
PrimitiveTypeKind.I16 => "i16", PrimitiveTypeKind.I16 => "i16",
@@ -153,7 +153,7 @@ public class NubPrimitiveType(PrimitiveTypeKind kind) : NubType
PrimitiveTypeKind.Bool => "bool", PrimitiveTypeKind.Bool => "bool",
PrimitiveTypeKind.String => "string", PrimitiveTypeKind.String => "string",
PrimitiveTypeKind.Any => "any", 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)) 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)) 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); 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) private NubType? TypeCheckIdentifier(IdentifierNode identifier)