fuck me
This commit is contained in:
@@ -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
3
run.sh
@@ -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 $?"'
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user