...
This commit is contained in:
@@ -1,42 +1,18 @@
|
|||||||
namespace main
|
namespace main
|
||||||
|
|
||||||
struct Human {
|
struct Human {
|
||||||
age: u64
|
name: string
|
||||||
print_age: func() = func() {
|
// print_age: func() = func() {
|
||||||
c::puts("pwp")
|
// c::puts("test3")
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
export func main(args: []^string): i64 {
|
export func main(args: [][]u8): i64 {
|
||||||
let x = 2
|
let x: []u8
|
||||||
|
|
||||||
let uwu = func() {
|
x = args[0]
|
||||||
c::puts("uwu")
|
|
||||||
}
|
|
||||||
|
|
||||||
uwu()
|
c::puts(x)
|
||||||
|
|
||||||
func() {
|
|
||||||
c::puts("owo")
|
|
||||||
}()
|
|
||||||
|
|
||||||
let me = alloc Human {
|
|
||||||
age = 23
|
|
||||||
}
|
|
||||||
|
|
||||||
me.print_age()
|
|
||||||
|
|
||||||
if true {
|
|
||||||
// do something
|
|
||||||
}
|
|
||||||
|
|
||||||
c::puts("test")
|
|
||||||
|
|
||||||
let i = 1
|
|
||||||
while i <= 10 {
|
|
||||||
c::puts("test")
|
|
||||||
i = i + 1
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,6 +85,9 @@ foreach (var compilationUnit in compilationUnits)
|
|||||||
Directory.CreateDirectory(outputDirectory);
|
Directory.CreateDirectory(outputDirectory);
|
||||||
|
|
||||||
var ssa = QBEGenerator.Generate(compilationUnit, definitionTable);
|
var ssa = QBEGenerator.Generate(compilationUnit, definitionTable);
|
||||||
|
var ssaPath = Path.ChangeExtension(outputPath, "ssa");
|
||||||
|
File.WriteAllText(ssaPath, ssa);
|
||||||
|
|
||||||
var asm = await QBE.Invoke(ssa);
|
var asm = await QBE.Invoke(ssa);
|
||||||
|
|
||||||
var asmPath = Path.ChangeExtension(outputPath, "s");
|
var asmPath = Path.ChangeExtension(outputPath, "s");
|
||||||
|
|||||||
@@ -4,12 +4,60 @@
|
|||||||
|
|
||||||
.global _start
|
.global _start
|
||||||
_start:
|
_start:
|
||||||
mov rdi, rsp
|
# On entry, the stack contains:
|
||||||
sub rsp, 8
|
# [rsp] = argc (argument count)
|
||||||
mov [rsp], rdi
|
# [rsp+8] = argv[0] (program name)
|
||||||
mov rdi, rsp
|
# [rsp+16] = argv[1] (first argument)
|
||||||
# func main(args: []^string): i64
|
# ...
|
||||||
|
|
||||||
|
# Get argc from stack
|
||||||
|
mov rdi, [rsp] # rdi = argc
|
||||||
|
|
||||||
|
# Calculate space needed for our array structure
|
||||||
|
# We need: 8 bytes (length) + argc * 8 bytes (pointers)
|
||||||
|
mov rax, rdi # rax = argc
|
||||||
|
shl rax, 3 # rax = argc * 8 (each pointer is 8 bytes)
|
||||||
|
add rax, 8 # rax = 8 + argc * 8 (add space for length)
|
||||||
|
|
||||||
|
# Allocate space on stack (align to 16 bytes)
|
||||||
|
add rax, 15 # Round up to nearest 16
|
||||||
|
and rax, -16 # Align to 16 bytes
|
||||||
|
sub rsp, rax # Allocate space
|
||||||
|
|
||||||
|
# Store array length at beginning
|
||||||
|
mov [rsp], rdi # Store argc as array length
|
||||||
|
|
||||||
|
# Copy argv pointers to our array
|
||||||
|
lea rsi, [rsp + 8] # rsi points to start of argv in stack
|
||||||
|
lea rdi, [rsp + 8] # rdi points to our array data (after length)
|
||||||
|
mov rcx, [rsp] # rcx = argc (loop counter)
|
||||||
|
|
||||||
|
copy_loop:
|
||||||
|
test rcx, rcx # Check if we're done
|
||||||
|
jz done_copying
|
||||||
|
|
||||||
|
mov rax, [rsi] # Load argv[i] pointer
|
||||||
|
mov [rdi], rax # Store in our array
|
||||||
|
add rsi, 8 # Move to next argv entry
|
||||||
|
add rdi, 8 # Move to next array slot
|
||||||
|
dec rcx # Decrement counter
|
||||||
|
jmp copy_loop
|
||||||
|
|
||||||
|
done_copying:
|
||||||
|
# Now rsp points to our array: [length][ptr0][ptr1]...[ptrN-1]
|
||||||
|
mov rdi, rsp # Pass array pointer to main
|
||||||
call main
|
call main
|
||||||
mov rdi, rax
|
|
||||||
mov rax, 60
|
# Clean up stack (restore original rsp)
|
||||||
|
# Calculate how much we allocated
|
||||||
|
mov rdi, [rsp] # Get argc back
|
||||||
|
shl rdi, 3 # argc * 8
|
||||||
|
add rdi, 8 # + 8 for length
|
||||||
|
add rdi, 15 # Round up
|
||||||
|
and rdi, -16 # Align
|
||||||
|
add rsp, rdi # Restore stack
|
||||||
|
|
||||||
|
# Exit with main's return value
|
||||||
|
mov rdi, rax # rax contains main's return value
|
||||||
|
mov rax, 60 # sys_exit
|
||||||
syscall
|
syscall
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ public static class QBEGenerator
|
|||||||
private static Stack<string> _breakLabels = [];
|
private static Stack<string> _breakLabels = [];
|
||||||
private static Stack<string> _continueLabels = [];
|
private static Stack<string> _continueLabels = [];
|
||||||
private static Queue<(AnonymousFuncNode Func, string Name)> _anonymousFunctions = [];
|
private static Queue<(AnonymousFuncNode Func, string Name)> _anonymousFunctions = [];
|
||||||
private static Stack<(string Name, string Pointer)> _variables = [];
|
private static Stack<Variable> _variables = [];
|
||||||
private static Stack<int> _variableScopes = [];
|
private static Stack<int> _variableScopes = [];
|
||||||
private static int _variableIndex;
|
private static int _variableIndex;
|
||||||
private static int _labelIndex;
|
private static int _labelIndex;
|
||||||
@@ -298,14 +298,14 @@ public static class QBEGenerator
|
|||||||
throw new UnreachableException($"Member '{member}' not found in struct");
|
throw new UnreachableException($"Member '{member}' not found in struct");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsLargeType(NubType type)
|
private static bool IsPointerType(NubType type)
|
||||||
{
|
{
|
||||||
return type switch
|
return type switch
|
||||||
{
|
{
|
||||||
NubArrayType => false,
|
|
||||||
NubPointerType => false,
|
NubPointerType => false,
|
||||||
NubPrimitiveType => false,
|
NubPrimitiveType => false,
|
||||||
NubStructType => true,
|
NubStructType => true,
|
||||||
|
NubArrayType => true,
|
||||||
NubFixedArrayType => true,
|
NubFixedArrayType => true,
|
||||||
NubFuncType => false,
|
NubFuncType => false,
|
||||||
_ => throw new ArgumentOutOfRangeException(nameof(type))
|
_ => throw new ArgumentOutOfRangeException(nameof(type))
|
||||||
@@ -387,7 +387,7 @@ public static class QBEGenerator
|
|||||||
_builder.AppendLine($"({string.Join(", ", parameterStrings)}) {{");
|
_builder.AppendLine($"({string.Join(", ", parameterStrings)}) {{");
|
||||||
_builder.AppendLine("@start");
|
_builder.AppendLine("@start");
|
||||||
|
|
||||||
List<(string Name, string Pointer)> parameterVars = [];
|
List<Variable> parameterVars = [];
|
||||||
|
|
||||||
foreach (var parameter in parameters)
|
foreach (var parameter in parameters)
|
||||||
{
|
{
|
||||||
@@ -416,7 +416,7 @@ public static class QBEGenerator
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
parameterVars.Add((parameter.Name, parameterName));
|
parameterVars.Add(new Variable(parameter.Name, parameterName).Assign());
|
||||||
}
|
}
|
||||||
|
|
||||||
GenerateBlock(body, parameterVars);
|
GenerateBlock(body, parameterVars);
|
||||||
@@ -553,7 +553,7 @@ public static class QBEGenerator
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void GenerateBlock(BlockNode block, List<(string Name, string Pointer)>? variables = null)
|
private static void GenerateBlock(BlockNode block, List<Variable>? variables = null)
|
||||||
{
|
{
|
||||||
_variableScopes.Push(_variables.Count);
|
_variableScopes.Push(_variables.Count);
|
||||||
if (variables != null)
|
if (variables != null)
|
||||||
@@ -654,29 +654,17 @@ public static class QBEGenerator
|
|||||||
|
|
||||||
private static void GenerateVariableDeclaration(VariableDeclarationNode variableDeclaration)
|
private static void GenerateVariableDeclaration(VariableDeclarationNode variableDeclaration)
|
||||||
{
|
{
|
||||||
var type = variableDeclaration.ExplicitType.Value ?? variableDeclaration.Value.Value!.Type;
|
var generatedName = VarName();
|
||||||
var pointer = VarName();
|
_builder.AppendLine($" {generatedName} =l alloc8 {SizeOf(variableDeclaration.Type)}");
|
||||||
_builder.AppendLine($" {pointer} =l alloc8 {SizeOf(type)}");
|
_variables.Push(new Variable(variableDeclaration.Name, generatedName));
|
||||||
|
|
||||||
if (variableDeclaration.Value.HasValue)
|
|
||||||
{
|
|
||||||
var value = GenerateExpression(variableDeclaration.Value.Value);
|
|
||||||
GenerateCopy(variableDeclaration.Value.Value.Type, value, pointer);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var pointerName = VarName();
|
|
||||||
_variables.Push((variableDeclaration.Name, pointerName));
|
|
||||||
}
|
|
||||||
|
|
||||||
_variables.Push((variableDeclaration.Name, pointer));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void GenerateVariableAssignment(VariableAssignmentNode variableAssignment)
|
private static void GenerateVariableAssignment(VariableAssignmentNode variableAssignment)
|
||||||
{
|
{
|
||||||
var value = GenerateExpression(variableAssignment.Value);
|
var value = GenerateExpression(variableAssignment.Value);
|
||||||
var variable = _variables.Single(x => x.Name == variableAssignment.Identifier.Name);
|
var variable = _variables.Single(x => x.Name == variableAssignment.Identifier.Name);
|
||||||
GenerateCopy(variableAssignment.Value.Type, value, variable.Pointer);
|
GenerateCopy(variableAssignment.Value.Type, value, variable.GeneratedName);
|
||||||
|
variable.Assign();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void GenerateWhile(WhileNode whileStatement)
|
private static void GenerateWhile(WhileNode whileStatement)
|
||||||
@@ -706,7 +694,7 @@ public static class QBEGenerator
|
|||||||
{
|
{
|
||||||
AddressOfNode addressOf => GenerateAddressOf(addressOf),
|
AddressOfNode addressOf => GenerateAddressOf(addressOf),
|
||||||
AnonymousFuncNode anonymousFunc => GenerateAnonymousFunc(anonymousFunc),
|
AnonymousFuncNode anonymousFunc => GenerateAnonymousFunc(anonymousFunc),
|
||||||
ArrayIndexAccessNode arrayIndex => GenerateArrayAccessIndex(arrayIndex),
|
ArrayIndexAccessNode arrayIndex => GenerateArrayIndexAccessNode(arrayIndex),
|
||||||
ArrayInitializerNode arrayInitializer => GenerateArrayInitializer(arrayInitializer),
|
ArrayInitializerNode arrayInitializer => GenerateArrayInitializer(arrayInitializer),
|
||||||
BinaryExpressionNode binaryExpression => GenerateBinaryExpression(binaryExpression),
|
BinaryExpressionNode binaryExpression => GenerateBinaryExpression(binaryExpression),
|
||||||
DereferenceNode dereference => GenerateDereference(dereference),
|
DereferenceNode dereference => GenerateDereference(dereference),
|
||||||
@@ -725,10 +713,7 @@ public static class QBEGenerator
|
|||||||
{
|
{
|
||||||
var name = $"$anon_func{++_anonymousFuncIndex}";
|
var name = $"$anon_func{++_anonymousFuncIndex}";
|
||||||
_anonymousFunctions.Enqueue((anonymousFunc, name));
|
_anonymousFunctions.Enqueue((anonymousFunc, name));
|
||||||
var pointer = VarName();
|
return name;
|
||||||
_builder.AppendLine($" {pointer} =l alloc8 8");
|
|
||||||
_builder.AppendLine($" storel {name}, {pointer}");
|
|
||||||
return pointer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GenerateArrayIndexPointer(ArrayIndexAccessNode arrayIndexAccess)
|
private static string GenerateArrayIndexPointer(ArrayIndexAccessNode arrayIndexAccess)
|
||||||
@@ -737,40 +722,27 @@ public static class QBEGenerator
|
|||||||
var index = GenerateExpression(arrayIndexAccess.Index);
|
var index = GenerateExpression(arrayIndexAccess.Index);
|
||||||
GenerateArrayBoundsCheck(array, index);
|
GenerateArrayBoundsCheck(array, index);
|
||||||
|
|
||||||
switch (arrayIndexAccess.Array.Type)
|
var elementType = arrayIndexAccess.Array.Type switch
|
||||||
{
|
{
|
||||||
case NubArrayType arrayType:
|
NubArrayType arrayType => arrayType.ElementType,
|
||||||
{
|
NubFixedArrayType fixedArrayType => fixedArrayType.ElementType,
|
||||||
var firstItemPointerName = VarName();
|
_ => throw new ArgumentOutOfRangeException()
|
||||||
_builder.AppendLine($" {firstItemPointerName} =l add {array}, 8");
|
};
|
||||||
var offsetPointerName = VarName();
|
|
||||||
_builder.AppendLine($" {offsetPointerName} =l mul {index}, {SizeOf(arrayType.ElementType)}");
|
var firstItemPointerName = VarName();
|
||||||
var resultPointerName = VarName();
|
_builder.AppendLine($" {firstItemPointerName} =l add {array}, 8");
|
||||||
_builder.AppendLine($" {resultPointerName} =l add {firstItemPointerName}, {offsetPointerName}");
|
var offsetPointerName = VarName();
|
||||||
return resultPointerName;
|
_builder.AppendLine($" {offsetPointerName} =l mul {index}, {SizeOf(elementType)}");
|
||||||
}
|
var resultPointerName = VarName();
|
||||||
case NubFixedArrayType fixedArrayType:
|
_builder.AppendLine($" {resultPointerName} =l add {firstItemPointerName}, {offsetPointerName}");
|
||||||
{
|
return resultPointerName;
|
||||||
var firstItemPointerName = VarName();
|
|
||||||
_builder.AppendLine($" {firstItemPointerName} =l add {array}, 8");
|
|
||||||
var offsetPointerName = VarName();
|
|
||||||
_builder.AppendLine($" {offsetPointerName} =l mul {index}, {SizeOf(fixedArrayType.ElementType)}");
|
|
||||||
var resultPointerName = VarName();
|
|
||||||
_builder.AppendLine($" {resultPointerName} =l add {firstItemPointerName}, {offsetPointerName}");
|
|
||||||
return resultPointerName;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
throw new ArgumentOutOfRangeException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GenerateArrayAccessIndex(ArrayIndexAccessNode arrayIndexAccess)
|
private static string GenerateArrayIndexAccessNode(ArrayIndexAccessNode arrayIndexAccess)
|
||||||
{
|
{
|
||||||
var pointerName = GenerateArrayIndexPointer(arrayIndexAccess);
|
var pointerName = GenerateArrayIndexPointer(arrayIndexAccess);
|
||||||
|
|
||||||
if (IsLargeType(arrayIndexAccess.Type))
|
if (IsPointerType(arrayIndexAccess.Type))
|
||||||
{
|
{
|
||||||
return pointerName;
|
return pointerName;
|
||||||
}
|
}
|
||||||
@@ -784,26 +756,26 @@ public static class QBEGenerator
|
|||||||
|
|
||||||
private static void GenerateArrayBoundsCheck(string array, string index)
|
private static void GenerateArrayBoundsCheck(string array, string index)
|
||||||
{
|
{
|
||||||
var countName = VarName();
|
// var countName = VarName();
|
||||||
_builder.AppendLine($" {countName} =l loadl {array}");
|
// _builder.AppendLine($" {countName} =l loadl {array}");
|
||||||
|
//
|
||||||
var isNegativeName = VarName();
|
// var isNegativeName = VarName();
|
||||||
_builder.AppendLine($" {isNegativeName} =w csltl {index}, 0");
|
// _builder.AppendLine($" {isNegativeName} =w csltl {index}, 0");
|
||||||
|
//
|
||||||
var isOobName = VarName();
|
// var isOobName = VarName();
|
||||||
_builder.AppendLine($" {isOobName} =w csgel {index}, {countName}");
|
// _builder.AppendLine($" {isOobName} =w csgel {index}, {countName}");
|
||||||
|
//
|
||||||
var anyOobName = VarName();
|
// var anyOobName = VarName();
|
||||||
_builder.AppendLine($" {anyOobName} =w or {isNegativeName}, {isOobName}");
|
// _builder.AppendLine($" {anyOobName} =w or {isNegativeName}, {isOobName}");
|
||||||
|
//
|
||||||
var oobLabel = LabelName();
|
// var oobLabel = LabelName();
|
||||||
var notOobLabel = LabelName();
|
// var notOobLabel = LabelName();
|
||||||
_builder.AppendLine($" jnz {anyOobName}, {oobLabel}, {notOobLabel}");
|
// _builder.AppendLine($" jnz {anyOobName}, {oobLabel}, {notOobLabel}");
|
||||||
|
//
|
||||||
_builder.AppendLine(oobLabel);
|
// _builder.AppendLine(oobLabel);
|
||||||
_builder.AppendLine($" call $nub_panic_array_oob()");
|
// _builder.AppendLine($" call $nub_panic_array_oob()");
|
||||||
|
//
|
||||||
_builder.AppendLine(notOobLabel);
|
// _builder.AppendLine(notOobLabel);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GenerateArrayInitializer(ArrayInitializerNode arrayInitializer)
|
private static string GenerateArrayInitializer(ArrayInitializerNode arrayInitializer)
|
||||||
@@ -847,7 +819,7 @@ public static class QBEGenerator
|
|||||||
throw new NotSupportedException("There is nothing to address in another namespace");
|
throw new NotSupportedException("There is nothing to address in another namespace");
|
||||||
}
|
}
|
||||||
|
|
||||||
return _variables.Single(x => x.Name == identifier.Name).Pointer;
|
return _variables.Single(x => x.Name == identifier.Name).GeneratedName;
|
||||||
case MemberAccessNode memberAccess:
|
case MemberAccessNode memberAccess:
|
||||||
return GenerateMemberAccessPointer(memberAccess);
|
return GenerateMemberAccessPointer(memberAccess);
|
||||||
default:
|
default:
|
||||||
@@ -1085,16 +1057,22 @@ public static class QBEGenerator
|
|||||||
{
|
{
|
||||||
if (_definitionTable.LookupFunc(identifier.Namespace.Or(_compilationUnit.Namespace), identifier.Name).TryGetValue(out var func))
|
if (_definitionTable.LookupFunc(identifier.Namespace.Or(_compilationUnit.Namespace), identifier.Name).TryGetValue(out var func))
|
||||||
{
|
{
|
||||||
var pointer = VarName();
|
return FuncName(func);
|
||||||
_builder.AppendLine($" {pointer} =l alloc8 8");
|
|
||||||
_builder.AppendLine($" storel {FuncName(func)}, {pointer}");
|
|
||||||
return pointer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!identifier.Namespace.HasValue)
|
if (!identifier.Namespace.HasValue)
|
||||||
{
|
{
|
||||||
var variable = _variables.Single(v => v.Name == identifier.Name);
|
var variable = _variables.Single(v => v.Name == identifier.Name);
|
||||||
return GenerateDereference(identifier.Type, variable.Pointer);
|
if (IsPointerType(identifier.Type))
|
||||||
|
{
|
||||||
|
return variable.GeneratedName;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var output = VarName();
|
||||||
|
_builder.AppendLine($" {output} {QBEAssign(identifier.Type)} {QBELoad(identifier.Type)} {variable.GeneratedName}");
|
||||||
|
return output;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new UnreachableException();
|
throw new UnreachableException();
|
||||||
@@ -1257,7 +1235,7 @@ public static class QBEGenerator
|
|||||||
{
|
{
|
||||||
var pointer = GenerateMemberAccessPointer(memberAccess);
|
var pointer = GenerateMemberAccessPointer(memberAccess);
|
||||||
|
|
||||||
if (IsLargeType(memberAccess.Type))
|
if (IsPointerType(memberAccess.Type))
|
||||||
{
|
{
|
||||||
return pointer;
|
return pointer;
|
||||||
}
|
}
|
||||||
@@ -1324,35 +1302,24 @@ public static class QBEGenerator
|
|||||||
parameterStrings.Add($"{qbeType} {result}");
|
parameterStrings.Add($"{qbeType} {result}");
|
||||||
}
|
}
|
||||||
|
|
||||||
string funcTarget;
|
var funcPointer = GenerateExpression(funcCall.Expression);
|
||||||
if (funcCall.Expression is IdentifierNode identifier && _definitionTable.LookupFunc(identifier.Namespace.Or(_compilationUnit.Namespace), identifier.Name).TryGetValue(out var func))
|
|
||||||
{
|
|
||||||
funcTarget = FuncName(func);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var funcPointerPointer = GenerateExpression(funcCall.Expression);
|
|
||||||
var funcPointer = VarName();
|
|
||||||
_builder.AppendLine($" {funcPointer} =l loadl {funcPointerPointer}");
|
|
||||||
funcTarget = funcPointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (funcType.ReturnType is not NubVoidType)
|
if (funcType.ReturnType is not NubVoidType)
|
||||||
{
|
{
|
||||||
var outputName = VarName();
|
var outputName = VarName();
|
||||||
_builder.AppendLine($" {outputName} {QBEAssign(funcCall.Type)} call {funcTarget}({string.Join(", ", parameterStrings)})");
|
_builder.AppendLine($" {outputName} {QBEAssign(funcCall.Type)} call {funcPointer}({string.Join(", ", parameterStrings)})");
|
||||||
return outputName;
|
return outputName;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_builder.AppendLine($" call {funcTarget}({string.Join(", ", parameterStrings)})");
|
_builder.AppendLine($" call {funcPointer}({string.Join(", ", parameterStrings)})");
|
||||||
return "fuck";
|
return "fuck";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void GenerateCopy(NubType type, string value, string destinationPointer)
|
private static void GenerateCopy(NubType type, string value, string destinationPointer)
|
||||||
{
|
{
|
||||||
if (IsLargeType(type))
|
if (IsPointerType(type))
|
||||||
{
|
{
|
||||||
_builder.AppendLine($" blit {value}, {destinationPointer}, {SizeOf(type)}");
|
_builder.AppendLine($" blit {value}, {destinationPointer}, {SizeOf(type)}");
|
||||||
}
|
}
|
||||||
@@ -1361,18 +1328,17 @@ public static class QBEGenerator
|
|||||||
_builder.AppendLine($" {QBEStore(type)} {value}, {destinationPointer}");
|
_builder.AppendLine($" {QBEStore(type)} {value}, {destinationPointer}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static string GenerateDereference(NubType type, string pointer)
|
internal class Variable(string name, string generatedName)
|
||||||
|
{
|
||||||
|
public string Name { get; init; } = name;
|
||||||
|
public string GeneratedName { get; init; } = generatedName;
|
||||||
|
public bool Initialized { get; private set; }
|
||||||
|
|
||||||
|
public Variable Assign()
|
||||||
{
|
{
|
||||||
if (IsLargeType(type))
|
Initialized = true;
|
||||||
{
|
return this;
|
||||||
return pointer;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var result = VarName();
|
|
||||||
_builder.AppendLine($" {result} {QBEAssign(type)} {QBELoad(type)} {pointer}");
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -271,19 +271,10 @@ public static class Parser
|
|||||||
{
|
{
|
||||||
ExpectSymbol(Symbol.Let);
|
ExpectSymbol(Symbol.Let);
|
||||||
var name = ExpectIdentifier().Value;
|
var name = ExpectIdentifier().Value;
|
||||||
var type = Optional<NubType>.Empty();
|
ExpectSymbol(Symbol.Colon);
|
||||||
if (TryExpectSymbol(Symbol.Colon))
|
var type = ParseType();
|
||||||
{
|
|
||||||
type = ParseType();
|
|
||||||
}
|
|
||||||
|
|
||||||
var value = Optional<ExpressionNode>.Empty();
|
return new VariableDeclarationNode(GetTokensForNode(startIndex), name, type);
|
||||||
if (TryExpectSymbol(Symbol.Assign))
|
|
||||||
{
|
|
||||||
value = ParseExpression();
|
|
||||||
}
|
|
||||||
|
|
||||||
return new VariableDeclarationNode(GetTokensForNode(startIndex), name, type, value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static StatementNode ParseBreak(int startIndex)
|
private static StatementNode ParseBreak(int startIndex)
|
||||||
@@ -674,6 +665,11 @@ public static class Parser
|
|||||||
return new NubVoidType();
|
return new NubVoidType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (name.Value == "string")
|
||||||
|
{
|
||||||
|
return new NubArrayType(NubPrimitiveType.U8);
|
||||||
|
}
|
||||||
|
|
||||||
if (NubPrimitiveType.TryParse(name.Value, out var primitiveTypeKind))
|
if (NubPrimitiveType.TryParse(name.Value, out var primitiveTypeKind))
|
||||||
{
|
{
|
||||||
return new NubPrimitiveType(primitiveTypeKind.Value);
|
return new NubPrimitiveType(primitiveTypeKind.Value);
|
||||||
|
|||||||
@@ -1,13 +1,10 @@
|
|||||||
using Common;
|
using Syntax.Tokenization;
|
||||||
using Syntax.Parsing.Expressions;
|
|
||||||
using Syntax.Tokenization;
|
|
||||||
using Syntax.Typing;
|
using Syntax.Typing;
|
||||||
|
|
||||||
namespace Syntax.Parsing.Statements;
|
namespace Syntax.Parsing.Statements;
|
||||||
|
|
||||||
public class VariableDeclarationNode(IReadOnlyList<Token> tokens, string name, Optional<NubType> explicitType, Optional<ExpressionNode> value) : StatementNode(tokens)
|
public class VariableDeclarationNode(IReadOnlyList<Token> tokens, string name, NubType type) : StatementNode(tokens)
|
||||||
{
|
{
|
||||||
public string Name { get; } = name;
|
public string Name { get; } = name;
|
||||||
public Optional<NubType> ExplicitType { get; } = explicitType;
|
public NubType Type { get; } = type;
|
||||||
public Optional<ExpressionNode> Value { get; } = value;
|
|
||||||
}
|
}
|
||||||
@@ -177,42 +177,12 @@ public static class TypeChecker
|
|||||||
|
|
||||||
private static void CheckVariableVariableDeclaration(VariableDeclarationNode variableDeclaration)
|
private static void CheckVariableVariableDeclaration(VariableDeclarationNode variableDeclaration)
|
||||||
{
|
{
|
||||||
NubType? type = null;
|
|
||||||
|
|
||||||
if (_variables.TryGetValue(variableDeclaration.Name, out var variable))
|
if (_variables.TryGetValue(variableDeclaration.Name, out var variable))
|
||||||
{
|
{
|
||||||
ReportError($"Cannot redeclare variable '{variable}'", variableDeclaration);
|
ReportError($"Cannot redeclare variable '{variable}'", variableDeclaration);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (variableDeclaration.Value.HasValue)
|
_variables[variableDeclaration.Name] = variableDeclaration.Type;
|
||||||
{
|
|
||||||
var valueType = CheckExpression(variableDeclaration.Value.Value, variableDeclaration.ExplicitType.Value);
|
|
||||||
if (valueType == null) return;
|
|
||||||
type = valueType;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (variableDeclaration.ExplicitType.HasValue)
|
|
||||||
{
|
|
||||||
type = variableDeclaration.ExplicitType.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (variableDeclaration.ExplicitType.HasValue && variableDeclaration.Value.HasValue)
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type == null)
|
|
||||||
{
|
|
||||||
ReportError($"Cannot implicitly get type of variable '{variableDeclaration.Name}'", variableDeclaration);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_variables[variableDeclaration.Name] = type;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static NubType? CheckDereference(DereferenceNode dereference)
|
private static NubType? CheckDereference(DereferenceNode dereference)
|
||||||
@@ -246,6 +216,7 @@ public static class TypeChecker
|
|||||||
if (funcCall.Parameters.Count != funcType.Parameters.Count)
|
if (funcCall.Parameters.Count != funcType.Parameters.Count)
|
||||||
{
|
{
|
||||||
ReportError($"{funcType} expects {funcType.Parameters.Count} arguments, but was called with {funcType.Parameters.Count} arguments", funcCall);
|
ReportError($"{funcType} expects {funcType.Parameters.Count} arguments, but was called with {funcType.Parameters.Count} arguments", funcCall);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0; i < funcCall.Parameters.Count; i++)
|
for (var i = 0; i < funcCall.Parameters.Count; i++)
|
||||||
|
|||||||
Reference in New Issue
Block a user