...
This commit is contained in:
9
README.md
Normal file
9
README.md
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
main.nm
|
||||||
|
missing:
|
||||||
|
- std::print
|
||||||
|
functions:
|
||||||
|
- main
|
||||||
|
|
||||||
|
std.nm
|
||||||
|
functions:
|
||||||
|
- print
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
CC = clang
|
CC = clang
|
||||||
NUBC = ../src/compiler/NubLang.CLI/bin/Debug/net9.0/nubc
|
NUBC = ../src/compiler/NubLang.CLI/bin/Debug/net9.0/nubc
|
||||||
|
|
||||||
out: build/out.a
|
.build/out: .build/out.a
|
||||||
$(CC) -o out build/out.a
|
$(CC) -g -o .build/out .build/out.a
|
||||||
|
|
||||||
build/out.a: $(NUBC) src/main.nub
|
.build/out.a: $(NUBC) src/main.nub
|
||||||
$(NUBC) src/main.nub
|
$(NUBC) src/main.nub
|
||||||
|
|
||||||
$(NUBC):
|
$(NUBC):
|
||||||
dotnet build ../src/compiler/NubLang.CLI/NubLang.CLI.csproj
|
dotnet build ../src/compiler/NubLang.CLI/NubLang.CLI.csproj
|
||||||
|
|
||||||
run: out
|
run: .build/out
|
||||||
./out
|
./.build/out
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
@rm -r build 2>/dev/null || true
|
@rm -r .build 2>/dev/null || true
|
||||||
@rm out 2>/dev/null || true
|
@rm out 2>/dev/null || true
|
||||||
|
|||||||
@@ -23,12 +23,12 @@ func main(args: []cstring): i64
|
|||||||
age = "23"
|
age = "23"
|
||||||
}
|
}
|
||||||
|
|
||||||
test(x&)
|
puts(x.age)
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func test(human: ^Human)
|
// func test(human: ^Human)
|
||||||
{
|
// {
|
||||||
puts(human^.name.last)
|
// puts(human^.name.last)
|
||||||
}
|
// }
|
||||||
@@ -13,11 +13,4 @@
|
|||||||
<ProjectReference Include="..\NubLang\NubLang.csproj" />
|
<ProjectReference Include="..\NubLang\NubLang.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<None Remove="assets\runtime.o" />
|
|
||||||
<EmbeddedResource Include="assets\runtime.o" />
|
|
||||||
<None Remove="assets\x64.o" />
|
|
||||||
<EmbeddedResource Include="assets\x64.o" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using System.Reflection;
|
using NubLang.CLI;
|
||||||
using NubLang.CLI;
|
|
||||||
using NubLang.Code;
|
using NubLang.Code;
|
||||||
using NubLang.Diagnostics;
|
using NubLang.Diagnostics;
|
||||||
using NubLang.Generation;
|
using NubLang.Generation;
|
||||||
@@ -91,7 +90,7 @@ var objectFiles = new List<string>();
|
|||||||
for (var i = 0; i < typedSyntaxTrees.Count; i++)
|
for (var i = 0; i < typedSyntaxTrees.Count; i++)
|
||||||
{
|
{
|
||||||
var syntaxTree = typedSyntaxTrees[i];
|
var syntaxTree = typedSyntaxTrees[i];
|
||||||
var outFileName = Path.Combine("build", "code", Path.ChangeExtension(options.Files[i].Path, null));
|
var outFileName = Path.Combine(".build", "code", Path.ChangeExtension(options.Files[i].Path, null));
|
||||||
|
|
||||||
var outFileDir = Path.GetDirectoryName(outFileName);
|
var outFileDir = Path.GetDirectoryName(outFileName);
|
||||||
if (!string.IsNullOrEmpty(outFileDir))
|
if (!string.IsNullOrEmpty(outFileDir))
|
||||||
@@ -124,39 +123,7 @@ for (var i = 0; i < typedSyntaxTrees.Count; i++)
|
|||||||
objectFiles.Add(objFilePath);
|
objectFiles.Add(objFilePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
var resources = Assembly.GetExecutingAssembly().GetManifestResourceNames();
|
var outPath = options.OutputPath ?? Path.Combine(".build", "out.a");
|
||||||
|
|
||||||
string[] runtimeObjects = ["runtime.o", "x64.o"];
|
|
||||||
|
|
||||||
foreach (var runtimeObject in runtimeObjects)
|
|
||||||
{
|
|
||||||
var runtime = resources.First(r => r.EndsWith(runtimeObject));
|
|
||||||
|
|
||||||
await using var reader = Assembly
|
|
||||||
.GetExecutingAssembly()
|
|
||||||
.GetManifestResourceStream(runtime);
|
|
||||||
|
|
||||||
if (reader == null)
|
|
||||||
{
|
|
||||||
Console.Error.WriteLine($"Cannot open read stream to '{runtimeObject}'");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
var runtimePath = Path.Combine("build", "runtime", runtimeObject);
|
|
||||||
var runtimeDir = Path.GetDirectoryName(runtimePath);
|
|
||||||
if (!string.IsNullOrEmpty(runtimeDir))
|
|
||||||
{
|
|
||||||
Directory.CreateDirectory(runtimeDir);
|
|
||||||
}
|
|
||||||
|
|
||||||
await using var writer = new FileStream(runtimePath, FileMode.Create);
|
|
||||||
|
|
||||||
reader.CopyTo(writer);
|
|
||||||
|
|
||||||
objectFiles.Add(runtimePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
var outPath = options.OutputPath ?? Path.Combine("build", "out.a");
|
|
||||||
var outDir = Path.GetDirectoryName(outPath);
|
var outDir = Path.GetDirectoryName(outPath);
|
||||||
if (!string.IsNullOrEmpty(outDir))
|
if (!string.IsNullOrEmpty(outDir))
|
||||||
{
|
{
|
||||||
@@ -169,5 +136,4 @@ if (!archiveResult)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
Binary file not shown.
Binary file not shown.
@@ -166,9 +166,63 @@ public class QBEGenerator
|
|||||||
return into;
|
return into;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void EmitMemset(string destination, int value, string length)
|
||||||
|
{
|
||||||
|
var count = TmpName();
|
||||||
|
_writer.Indented($"{count} =l copy 0");
|
||||||
|
|
||||||
|
var loopLabel = LabelName();
|
||||||
|
_writer.WriteLine(loopLabel);
|
||||||
|
|
||||||
|
var continueLabel = LabelName();
|
||||||
|
var doneLabel = LabelName();
|
||||||
|
var condition = TmpName();
|
||||||
|
_writer.Indented($"{condition} =w cultl {count}, {length}");
|
||||||
|
_writer.Indented($"jnz {condition}, {continueLabel}, {doneLabel}");
|
||||||
|
|
||||||
|
_writer.WriteLine(continueLabel);
|
||||||
|
|
||||||
|
var destinationAddress = TmpName();
|
||||||
|
_writer.Indented($"{destinationAddress} =l add {destination}, {count}");
|
||||||
|
|
||||||
|
_writer.Indented($"storeb {value}, {destinationAddress}");
|
||||||
|
|
||||||
|
_writer.Indented($"{count} =l add {count}, 1");
|
||||||
|
_writer.Indented($"jmp {loopLabel}");
|
||||||
|
|
||||||
|
_writer.WriteLine(doneLabel);
|
||||||
|
}
|
||||||
|
|
||||||
private void EmitMemcpy(string source, string destination, string length)
|
private void EmitMemcpy(string source, string destination, string length)
|
||||||
{
|
{
|
||||||
_writer.Indented($"call $nub_memcpy(l {source}, l {destination}, l {length})");
|
var count = TmpName();
|
||||||
|
_writer.Indented($"{count} =l copy 0");
|
||||||
|
|
||||||
|
var loopLabel = LabelName();
|
||||||
|
_writer.WriteLine(loopLabel);
|
||||||
|
|
||||||
|
var continueLabel = LabelName();
|
||||||
|
var doneLabel = LabelName();
|
||||||
|
var condition = TmpName();
|
||||||
|
_writer.Indented($"{condition} =w cultl {count}, {length}");
|
||||||
|
_writer.Indented($"jnz {condition}, {continueLabel}, {doneLabel}");
|
||||||
|
|
||||||
|
_writer.WriteLine(continueLabel);
|
||||||
|
|
||||||
|
var sourceAddress = TmpName();
|
||||||
|
_writer.Indented($"{sourceAddress} =l add {source}, {count}");
|
||||||
|
|
||||||
|
var destinationAddress = TmpName();
|
||||||
|
_writer.Indented($"{destinationAddress} =l add {destination}, {count}");
|
||||||
|
|
||||||
|
var value = TmpName();
|
||||||
|
_writer.Indented($"{value} =w loadub {sourceAddress}");
|
||||||
|
_writer.Indented($"storeb {value}, {destinationAddress}");
|
||||||
|
|
||||||
|
_writer.Indented($"{count} =l add {count}, 1");
|
||||||
|
_writer.Indented($"jmp {loopLabel}");
|
||||||
|
|
||||||
|
_writer.WriteLine(doneLabel);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string EmitArraySizeInBytes(ArrayTypeNode type, string array)
|
private string EmitArraySizeInBytes(ArrayTypeNode type, string array)
|
||||||
@@ -182,10 +236,27 @@ public class QBEGenerator
|
|||||||
|
|
||||||
private string EmitCStringSizeInBytes(string cstring)
|
private string EmitCStringSizeInBytes(string cstring)
|
||||||
{
|
{
|
||||||
var size = TmpName();
|
var count = TmpName();
|
||||||
_writer.Indented($"{size} =l call $nub_cstring_length(l {cstring})");
|
_writer.Indented($"{count} =l copy 0");
|
||||||
_writer.Indented($"{size} =l add {size}, 1");
|
|
||||||
return size;
|
var loopLabel = LabelName();
|
||||||
|
_writer.WriteLine(loopLabel);
|
||||||
|
|
||||||
|
var address = TmpName();
|
||||||
|
_writer.Indented($"{address} =l add {cstring}, {count}");
|
||||||
|
|
||||||
|
var value = TmpName();
|
||||||
|
_writer.Indented($"{value} =w loadub {address}");
|
||||||
|
|
||||||
|
var notZeroLabel = LabelName();
|
||||||
|
var zeroLabel = LabelName();
|
||||||
|
_writer.Indented($"jnz {value}, {notZeroLabel}, {zeroLabel}");
|
||||||
|
_writer.WriteLine(notZeroLabel);
|
||||||
|
_writer.Indented($"{count} =l add {count}, 1");
|
||||||
|
_writer.Indented($"jmp {loopLabel}");
|
||||||
|
_writer.WriteLine(zeroLabel);
|
||||||
|
|
||||||
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string EmitStringSizeInBytes(string nubstring)
|
private string EmitStringSizeInBytes(string nubstring)
|
||||||
@@ -196,57 +267,26 @@ public class QBEGenerator
|
|||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool EmitTryMoveInto(ExpressionNode source, string destinationLValue)
|
private void EmitCopyInto(ExpressionNode source, string destination)
|
||||||
{
|
{
|
||||||
switch (source)
|
// Simple types are passed in registers and can therefore just be stored
|
||||||
{
|
if (source.Type.IsSimpleType(out var simpleType, out var complexType))
|
||||||
case ArrayInitializerNode arrayInitializer:
|
|
||||||
{
|
|
||||||
EmitStore(source.Type, EmitArrayInitializer(arrayInitializer), destinationLValue);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
case StructInitializerNode structInitializer:
|
|
||||||
{
|
|
||||||
EmitStructInitializer(structInitializer, destinationLValue);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
case ConvertToInterfaceNode convertToInterface:
|
|
||||||
{
|
|
||||||
EmitConvertToInterface(convertToInterface, destinationLValue);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
case LiteralNode { Kind: LiteralKind.String } literal:
|
|
||||||
{
|
|
||||||
EmitStore(source.Type, EmitLiteral(literal), destinationLValue);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void EmitCopyIntoOrInitialize(ExpressionNode source, string destinationLValue)
|
|
||||||
{
|
|
||||||
// If the source is a value which is not used yet such as an array/struct initializer or literal, we can skip copying
|
|
||||||
if (EmitTryMoveInto(source, destinationLValue))
|
|
||||||
{
|
{
|
||||||
|
var value = EmitExpression(source);
|
||||||
|
EmitStore(simpleType, value, destination);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var value = EmitExpression(source);
|
// Structs and interfaces has known sizes at compile time
|
||||||
|
|
||||||
if (source.Type.IsSimpleType(out var simpleType, out var complexType))
|
|
||||||
{
|
|
||||||
EmitStore(simpleType, value, destinationLValue);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (complexType is StructTypeNode or InterfaceTypeNode)
|
if (complexType is StructTypeNode or InterfaceTypeNode)
|
||||||
{
|
{
|
||||||
EmitMemcpy(value, destinationLValue, SizeOf(complexType).ToString());
|
var value = EmitExpression(source);
|
||||||
|
_writer.Indented($"blit {value}, {destination}, {SizeOf(complexType)}");
|
||||||
}
|
}
|
||||||
|
// The rest of the complex types has unknown sizes
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
var value = EmitExpression(source);
|
||||||
var size = complexType switch
|
var size = complexType switch
|
||||||
{
|
{
|
||||||
ArrayTypeNode arrayType => EmitArraySizeInBytes(arrayType, value),
|
ArrayTypeNode arrayType => EmitArraySizeInBytes(arrayType, value),
|
||||||
@@ -258,12 +298,11 @@ public class QBEGenerator
|
|||||||
var buffer = TmpName();
|
var buffer = TmpName();
|
||||||
_writer.Indented($"{buffer} =l alloc8 {size}");
|
_writer.Indented($"{buffer} =l alloc8 {size}");
|
||||||
EmitMemcpy(value, buffer, size);
|
EmitMemcpy(value, buffer, size);
|
||||||
EmitStore(complexType, buffer, destinationLValue);
|
EmitStore(complexType, buffer, destination);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string EmitCreateCopy(ExpressionNode source)
|
private string EmitCopy(ExpressionNode source)
|
||||||
{
|
{
|
||||||
// Allowlist for types which are safe to not copy
|
// Allowlist for types which are safe to not copy
|
||||||
if (source is ArrayInitializerNode or StructInitializerNode or ConvertToInterfaceNode or LiteralNode)
|
if (source is ArrayInitializerNode or StructInitializerNode or ConvertToInterfaceNode or LiteralNode)
|
||||||
@@ -279,19 +318,30 @@ public class QBEGenerator
|
|||||||
|
|
||||||
// For the rest, we figure out the size of the type and shallow copy them
|
// For the rest, we figure out the size of the type and shallow copy them
|
||||||
var value = EmitExpression(source);
|
var value = EmitExpression(source);
|
||||||
|
var destination = TmpName();
|
||||||
|
|
||||||
|
// Structs and interfaces has known sizes at compile time
|
||||||
|
if (complexType is StructTypeNode or InterfaceTypeNode)
|
||||||
|
{
|
||||||
|
var size = SizeOf(complexType);
|
||||||
|
_writer.Indented($"{destination} =l alloc8 {size}");
|
||||||
|
_writer.Indented($"blit {value}, {destination}, {size}");
|
||||||
|
}
|
||||||
|
// The rest of the complex types has unknown sizes
|
||||||
|
else
|
||||||
|
{
|
||||||
var size = complexType switch
|
var size = complexType switch
|
||||||
{
|
{
|
||||||
ArrayTypeNode arrayType => EmitArraySizeInBytes(arrayType, value),
|
ArrayTypeNode arrayType => EmitArraySizeInBytes(arrayType, value),
|
||||||
CStringTypeNode => EmitCStringSizeInBytes(value),
|
CStringTypeNode => EmitCStringSizeInBytes(value),
|
||||||
StringTypeNode => EmitStringSizeInBytes(value),
|
StringTypeNode => EmitStringSizeInBytes(value),
|
||||||
InterfaceTypeNode interfaceType => SizeOf(interfaceType).ToString(),
|
|
||||||
StructTypeNode structType => SizeOf(structType).ToString(),
|
|
||||||
_ => throw new ArgumentOutOfRangeException(nameof(source.Type))
|
_ => throw new ArgumentOutOfRangeException(nameof(source.Type))
|
||||||
};
|
};
|
||||||
|
|
||||||
var destination = TmpName();
|
|
||||||
_writer.Indented($"{destination} =l alloc8 {size}");
|
_writer.Indented($"{destination} =l alloc8 {size}");
|
||||||
EmitMemcpy(value, destination, size);
|
EmitMemcpy(value, destination, size);
|
||||||
|
}
|
||||||
|
|
||||||
return destination;
|
return destination;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -460,11 +510,11 @@ public class QBEGenerator
|
|||||||
|
|
||||||
private void EmitStatement(StatementNode statement)
|
private void EmitStatement(StatementNode statement)
|
||||||
{
|
{
|
||||||
var tokens = statement.Tokens.ToArray();
|
// var tokens = statement.Tokens.ToArray();
|
||||||
if (tokens.Length != 0)
|
// if (tokens.Length != 0)
|
||||||
{
|
// {
|
||||||
_writer.WriteLine($"dbgloc {tokens[0].FileSpan.Span.Start.Line}");
|
// _writer.WriteLine($"dbgloc {tokens[0].FileSpan.Span.Start.Line}");
|
||||||
}
|
// }
|
||||||
|
|
||||||
switch (statement)
|
switch (statement)
|
||||||
{
|
{
|
||||||
@@ -499,7 +549,7 @@ public class QBEGenerator
|
|||||||
|
|
||||||
private void EmitAssignment(AssignmentNode assignment)
|
private void EmitAssignment(AssignmentNode assignment)
|
||||||
{
|
{
|
||||||
EmitCopyIntoOrInitialize(assignment.Value, EmitAddressOfLValue(assignment.Target));
|
EmitCopyInto(assignment.Value, EmitAddressOfLValue(assignment.Target));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EmitBreak()
|
private void EmitBreak()
|
||||||
@@ -554,7 +604,7 @@ public class QBEGenerator
|
|||||||
|
|
||||||
if (variableDeclaration.Assignment.HasValue)
|
if (variableDeclaration.Assignment.HasValue)
|
||||||
{
|
{
|
||||||
EmitCopyIntoOrInitialize(variableDeclaration.Assignment.Value, name);
|
EmitCopyInto(variableDeclaration.Assignment.Value, name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -581,11 +631,11 @@ public class QBEGenerator
|
|||||||
|
|
||||||
private string EmitExpression(ExpressionNode expression)
|
private string EmitExpression(ExpressionNode expression)
|
||||||
{
|
{
|
||||||
var tokens = expression.Tokens.ToArray();
|
// var tokens = expression.Tokens.ToArray();
|
||||||
if (tokens.Length != 0)
|
// if (tokens.Length != 0)
|
||||||
{
|
// {
|
||||||
_writer.WriteLine($"dbgloc {tokens[0].FileSpan.Span.Start.Line}");
|
// _writer.WriteLine($"dbgloc {tokens[0].FileSpan.Span.Start.Line}");
|
||||||
}
|
// }
|
||||||
|
|
||||||
return expression switch
|
return expression switch
|
||||||
{
|
{
|
||||||
@@ -623,30 +673,6 @@ public class QBEGenerator
|
|||||||
return EmitLoad(arrayIndexAccess.Type, address);
|
return EmitLoad(arrayIndexAccess.Type, address);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EmitArrayBoundsCheck(string array, string index)
|
|
||||||
{
|
|
||||||
var count = TmpName();
|
|
||||||
_writer.Indented($"{count} =l loadl {array}");
|
|
||||||
|
|
||||||
var isNegative = TmpName();
|
|
||||||
_writer.Indented($"{isNegative} =w csltl {index}, 0");
|
|
||||||
|
|
||||||
var isOob = TmpName();
|
|
||||||
_writer.Indented($"{isOob} =w csgel {index}, {count}");
|
|
||||||
|
|
||||||
var anyOob = TmpName();
|
|
||||||
_writer.Indented($"{anyOob} =w or {isNegative}, {isOob}");
|
|
||||||
|
|
||||||
var oobLabel = LabelName();
|
|
||||||
var notOobLabel = LabelName();
|
|
||||||
_writer.Indented($"jnz {anyOob}, {oobLabel}, {notOobLabel}");
|
|
||||||
|
|
||||||
_writer.Indented(oobLabel);
|
|
||||||
_writer.Indented($"call $nub_panic_array_oob()");
|
|
||||||
|
|
||||||
_writer.Indented(notOobLabel);
|
|
||||||
}
|
|
||||||
|
|
||||||
private string EmitArrayInitializer(ArrayInitializerNode arrayInitializer)
|
private string EmitArrayInitializer(ArrayInitializerNode arrayInitializer)
|
||||||
{
|
{
|
||||||
var capacity = EmitExpression(arrayInitializer.Capacity);
|
var capacity = EmitExpression(arrayInitializer.Capacity);
|
||||||
@@ -663,7 +689,7 @@ public class QBEGenerator
|
|||||||
|
|
||||||
var dataPointer = TmpName();
|
var dataPointer = TmpName();
|
||||||
_writer.Indented($"{dataPointer} =l add {arrayPointer}, 8");
|
_writer.Indented($"{dataPointer} =l add {arrayPointer}, 8");
|
||||||
_writer.Indented($"call $nub_memset(l {dataPointer}, w 0, l {capacityInBytes})");
|
EmitMemset(dataPointer, 0, capacityInBytes);
|
||||||
|
|
||||||
return arrayPointer;
|
return arrayPointer;
|
||||||
}
|
}
|
||||||
@@ -700,8 +726,6 @@ public class QBEGenerator
|
|||||||
var array = EmitExpression(arrayIndexAccess.Target);
|
var array = EmitExpression(arrayIndexAccess.Target);
|
||||||
var index = EmitExpression(arrayIndexAccess.Index);
|
var index = EmitExpression(arrayIndexAccess.Index);
|
||||||
|
|
||||||
EmitArrayBoundsCheck(array, index);
|
|
||||||
|
|
||||||
var elementType = ((ArrayTypeNode)arrayIndexAccess.Target.Type).ElementType;
|
var elementType = ((ArrayTypeNode)arrayIndexAccess.Target.Type).ElementType;
|
||||||
|
|
||||||
var offset = TmpName();
|
var offset = TmpName();
|
||||||
@@ -1006,16 +1030,13 @@ public class QBEGenerator
|
|||||||
throw new NotSupportedException($"Cannot create literal of kind '{literal.Kind}' for type {literal.Type}");
|
throw new NotSupportedException($"Cannot create literal of kind '{literal.Kind}' for type {literal.Type}");
|
||||||
}
|
}
|
||||||
|
|
||||||
private string EmitStructInitializer(StructInitializerNode structInitializer, string? destination = null)
|
private string EmitStructInitializer(StructInitializerNode structInitializer)
|
||||||
{
|
{
|
||||||
var structDef = _definitionTable.LookupStruct(structInitializer.StructType.Name);
|
var structDef = _definitionTable.LookupStruct(structInitializer.StructType.Name);
|
||||||
|
|
||||||
if (destination == null)
|
var destination = TmpName();
|
||||||
{
|
|
||||||
destination = TmpName();
|
|
||||||
var size = SizeOf(structInitializer.StructType);
|
var size = SizeOf(structInitializer.StructType);
|
||||||
_writer.Indented($"{destination} =l alloc8 {size}");
|
_writer.Indented($"{destination} =l alloc8 {size}");
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var field in structDef.Fields)
|
foreach (var field in structDef.Fields)
|
||||||
{
|
{
|
||||||
@@ -1031,7 +1052,7 @@ public class QBEGenerator
|
|||||||
|
|
||||||
var offset = TmpName();
|
var offset = TmpName();
|
||||||
_writer.Indented($"{offset} =l add {destination}, {OffsetOf(structDef, field.Name)}");
|
_writer.Indented($"{offset} =l add {destination}, {OffsetOf(structDef, field.Name)}");
|
||||||
EmitCopyIntoOrInitialize(valueExpression, offset);
|
EmitCopyInto(valueExpression, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
return destination;
|
return destination;
|
||||||
@@ -1106,7 +1127,7 @@ public class QBEGenerator
|
|||||||
|
|
||||||
foreach (var parameter in structFuncCall.Parameters)
|
foreach (var parameter in structFuncCall.Parameters)
|
||||||
{
|
{
|
||||||
var copy = EmitCreateCopy(parameter);
|
var copy = EmitCopy(parameter);
|
||||||
parameterStrings.Add($"{FuncQBETypeName(parameter.Type)} {copy}");
|
parameterStrings.Add($"{FuncQBETypeName(parameter.Type)} {copy}");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1148,7 +1169,7 @@ public class QBEGenerator
|
|||||||
|
|
||||||
foreach (var parameter in interfaceFuncCall.Parameters)
|
foreach (var parameter in interfaceFuncCall.Parameters)
|
||||||
{
|
{
|
||||||
var copy = EmitCreateCopy(parameter);
|
var copy = EmitCopy(parameter);
|
||||||
parameterStrings.Add($"{FuncQBETypeName(parameter.Type)} {copy}");
|
parameterStrings.Add($"{FuncQBETypeName(parameter.Type)} {copy}");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1165,7 +1186,7 @@ public class QBEGenerator
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string EmitConvertToInterface(ConvertToInterfaceNode convertToInterface, string? destination = null)
|
private string EmitConvertToInterface(ConvertToInterfaceNode convertToInterface)
|
||||||
{
|
{
|
||||||
var implementation = EmitExpression(convertToInterface.Implementation);
|
var implementation = EmitExpression(convertToInterface.Implementation);
|
||||||
|
|
||||||
@@ -1180,11 +1201,8 @@ public class QBEGenerator
|
|||||||
vtableOffset += interfaceImplementation.Functions.Count * 8;
|
vtableOffset += interfaceImplementation.Functions.Count * 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (destination == null)
|
var destination = TmpName();
|
||||||
{
|
|
||||||
destination = TmpName();
|
|
||||||
_writer.Indented($"{destination} =l alloc8 {SizeOf(convertToInterface.InterfaceType)}");
|
_writer.Indented($"{destination} =l alloc8 {SizeOf(convertToInterface.InterfaceType)}");
|
||||||
}
|
|
||||||
|
|
||||||
var interfaceVtablePointer = TmpName();
|
var interfaceVtablePointer = TmpName();
|
||||||
_writer.Indented($"{interfaceVtablePointer} =l add {StructVtableName(convertToInterface.StructType.Name)}, {vtableOffset}");
|
_writer.Indented($"{interfaceVtablePointer} =l add {StructVtableName(convertToInterface.StructType.Name)}, {vtableOffset}");
|
||||||
@@ -1258,7 +1276,7 @@ public class QBEGenerator
|
|||||||
|
|
||||||
foreach (var parameter in funcCall.Parameters)
|
foreach (var parameter in funcCall.Parameters)
|
||||||
{
|
{
|
||||||
var copy = EmitCreateCopy(parameter);
|
var copy = EmitCopy(parameter);
|
||||||
parameterStrings.Add($"{FuncQBETypeName(parameter.Type)} {copy}");
|
parameterStrings.Add($"{FuncQBETypeName(parameter.Type)} {copy}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user