...
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
namespace c
|
namespace c
|
||||||
|
|
||||||
// extern func printf(fmt: ^u8, ...args: any): void
|
extern func printf(fmt: cstring, arg: u64): void
|
||||||
extern func puts(fmt: cstring)
|
extern func puts(fmt: cstring)
|
||||||
|
|||||||
@@ -5,35 +5,39 @@ struct Human {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export func main(args: []cstring): i64 {
|
export func main(args: []cstring): i64 {
|
||||||
let human: Human
|
// let human: Human
|
||||||
|
|
||||||
human = alloc Human {
|
// human = alloc Human {
|
||||||
name = "member"
|
// name = "member"
|
||||||
}
|
// }
|
||||||
|
|
||||||
c::puts(human.name)
|
// c::puts(human.name)
|
||||||
|
|
||||||
c::puts("literal")
|
// c::puts("literal")
|
||||||
|
|
||||||
let x: cstring
|
// let x: cstring
|
||||||
|
|
||||||
x = "variable"
|
// x = "variable"
|
||||||
|
|
||||||
c::puts(x)
|
// c::puts(x)
|
||||||
|
|
||||||
let y: func(cstring)
|
// let y: func(cstring)
|
||||||
|
|
||||||
y = c::puts
|
// y = c::puts
|
||||||
|
|
||||||
y("proxy")
|
// y("proxy")
|
||||||
|
|
||||||
func(){ c::puts("anon") }()
|
// func(){ c::puts("anon") }()
|
||||||
|
|
||||||
let z: func()
|
// let z: func()
|
||||||
|
|
||||||
z = func() { c::puts("anon variable") }
|
// z = func() { c::puts("anon variable") }
|
||||||
|
|
||||||
z()
|
// z()
|
||||||
|
|
||||||
|
c::printf("%d\n", "test".count)
|
||||||
|
|
||||||
|
// c::puts("test")
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,13 +14,11 @@
|
|||||||
<ProjectReference Include="..\Syntax\Syntax.csproj" />
|
<ProjectReference Include="..\Syntax\Syntax.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<EmbeddedResource Include="Runtime\entry.s" />
|
<EmbeddedResource Include="Runtime\entry.s" />
|
||||||
<EmbeddedResource Include="Runtime\nub_mem.s" />
|
<EmbeddedResource Include="Runtime\nub_mem.s" />
|
||||||
<EmbeddedResource Include="Runtime\nub_panic.s" />
|
<EmbeddedResource Include="Runtime\nub_panic.s" />
|
||||||
|
<EmbeddedResource Include="Runtime\nub_cstring.s" />
|
||||||
<EmbeddedResource Include="Runtime\nub_string.s" />
|
<EmbeddedResource Include="Runtime\nub_string.s" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
17
src/CLI/Runtime/nub_cstring.s
Normal file
17
src/CLI/Runtime/nub_cstring.s
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
.intel_syntax noprefix
|
||||||
|
|
||||||
|
.text
|
||||||
|
.globl nub_cstring_length
|
||||||
|
# func nub_cstring_length(string: cstring): u64
|
||||||
|
nub_cstring_length:
|
||||||
|
xor rax, rax
|
||||||
|
|
||||||
|
count_loop:
|
||||||
|
cmp byte ptr [rdi + rax], 0
|
||||||
|
je done
|
||||||
|
|
||||||
|
inc rax
|
||||||
|
jmp count_loop
|
||||||
|
|
||||||
|
done:
|
||||||
|
ret
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
nub_memcpy:
|
nub_memcpy:
|
||||||
mov rcx, rdx
|
mov rcx, rdx
|
||||||
rep movsb
|
rep movsb
|
||||||
|
ret
|
||||||
|
|
||||||
.text
|
.text
|
||||||
.globl nub_memset
|
.globl nub_memset
|
||||||
|
|||||||
@@ -1,80 +1,32 @@
|
|||||||
.intel_syntax noprefix
|
.intel_syntax noprefix
|
||||||
|
|
||||||
.equ SYS_MMAP, 9
|
|
||||||
|
|
||||||
.text
|
.text
|
||||||
.globl nub_strlen
|
.globl nub_string_length
|
||||||
# func nub_strlen(string: cstring): u64
|
# func nub_string_length(string: string): u64
|
||||||
nub_strlen:
|
nub_string_length:
|
||||||
test rdi, rdi
|
mov rsi, [rdi] # Length of string in bytes
|
||||||
jz null_string
|
|
||||||
xor rax, rax
|
add rdi, 8 # Start of bytes
|
||||||
strlen_loop:
|
xor rax, rax # Character count
|
||||||
cmp byte ptr [rdi + rax], 0
|
xor rdx, rdx # Current byte position
|
||||||
je strlen_exit
|
|
||||||
|
test rsi, rsi
|
||||||
|
jz _done
|
||||||
|
|
||||||
|
_count_loop:
|
||||||
|
cmp rdx, rsi
|
||||||
|
jge _done
|
||||||
|
|
||||||
|
mov dl, [rdi + rdx]
|
||||||
|
and dl, 0b11000000
|
||||||
|
cmp dl, 0b10000000
|
||||||
|
je _skip_byte
|
||||||
|
|
||||||
inc rax
|
inc rax
|
||||||
jmp strlen_loop
|
|
||||||
null_string:
|
_skip_byte:
|
||||||
xor rax, rax
|
inc rdx
|
||||||
strlen_exit:
|
jmp _count_loop
|
||||||
ret
|
|
||||||
|
_done:
|
||||||
.text
|
|
||||||
.globl nub_cstring_to_string
|
|
||||||
# func nub_cstring_to_string(string: cstring): []u8
|
|
||||||
nub_cstring_to_string:
|
|
||||||
push rbx
|
|
||||||
push r12
|
|
||||||
push r13
|
|
||||||
|
|
||||||
mov rbx, rdi # Save original pointer
|
|
||||||
call nub_strlen
|
|
||||||
mov r12, rax # r12 = string length
|
|
||||||
|
|
||||||
# Calculate total space needed: 8 bytes (length) + string length
|
|
||||||
mov r13, r12
|
|
||||||
add r13, 8 # r13 = total bytes needed
|
|
||||||
|
|
||||||
# Round up to page size (4096 bytes) for mmap
|
|
||||||
add r13, 4095 # Add page_size - 1
|
|
||||||
and r13, -4096 # Align to page boundary
|
|
||||||
|
|
||||||
mov rax, SYS_MMAP
|
|
||||||
xor rdi, rdi # addr = 0 (let kernel choose)
|
|
||||||
mov rsi, r13 # length = aligned size
|
|
||||||
mov rdx, 3 # prot = PROT_READ | PROT_WRITE
|
|
||||||
mov r10, 34 # flags = MAP_PRIVATE | MAP_ANONYMOUS (0x22)
|
|
||||||
mov r8, -1 # fd = -1
|
|
||||||
xor r9, r9 # offset = 0
|
|
||||||
syscall
|
|
||||||
|
|
||||||
# Check if mmap failed
|
|
||||||
cmp rax, -1
|
|
||||||
je mmap_failed
|
|
||||||
|
|
||||||
mov r13, rax # r13 = pointer to mapped memory
|
|
||||||
|
|
||||||
# Store length at beginning of mapped memory
|
|
||||||
mov [r13], r12 # Store string length
|
|
||||||
|
|
||||||
# Copy string data if not empty
|
|
||||||
test r12, r12 # Check if length is 0
|
|
||||||
jz copy_done
|
|
||||||
|
|
||||||
lea rdi, [r13 + 8]
|
|
||||||
mov rsi, rbx
|
|
||||||
mov rcx, r12
|
|
||||||
call nub_memcpy
|
|
||||||
|
|
||||||
copy_done:
|
|
||||||
mov rax, r13
|
|
||||||
jmp function_exit
|
|
||||||
|
|
||||||
mmap_failed:
|
|
||||||
xor rax, rax
|
|
||||||
|
|
||||||
function_exit:
|
|
||||||
pop r13
|
|
||||||
pop r12
|
|
||||||
pop rbx
|
|
||||||
ret
|
ret
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ public static class QBEGenerator
|
|||||||
|
|
||||||
private static StringBuilder _builder = new();
|
private static StringBuilder _builder = new();
|
||||||
private static List<CStringLiteral> _cStringLiterals = [];
|
private static List<CStringLiteral> _cStringLiterals = [];
|
||||||
|
private static List<StringLiteral> _stringLiterals = [];
|
||||||
private static Stack<string> _breakLabels = [];
|
private static Stack<string> _breakLabels = [];
|
||||||
private static Stack<string> _continueLabels = [];
|
private static Stack<string> _continueLabels = [];
|
||||||
private static Queue<(BoundAnonymousFuncNode Func, string Name)> _anonymousFunctions = [];
|
private static Queue<(BoundAnonymousFuncNode Func, string Name)> _anonymousFunctions = [];
|
||||||
@@ -25,6 +26,7 @@ public static class QBEGenerator
|
|||||||
private static int _labelIndex;
|
private static int _labelIndex;
|
||||||
private static int _anonymousFuncIndex;
|
private static int _anonymousFuncIndex;
|
||||||
private static int _cStringLiteralIndex;
|
private static int _cStringLiteralIndex;
|
||||||
|
private static int _stringLiteralIndex;
|
||||||
private static bool _codeIsReachable = true;
|
private static bool _codeIsReachable = true;
|
||||||
|
|
||||||
public static string Emit(BoundSyntaxTree syntaxTree, BoundDefinitionTable definitionTable)
|
public static string Emit(BoundSyntaxTree syntaxTree, BoundDefinitionTable definitionTable)
|
||||||
@@ -34,6 +36,7 @@ public static class QBEGenerator
|
|||||||
|
|
||||||
_builder = new StringBuilder();
|
_builder = new StringBuilder();
|
||||||
_cStringLiterals = [];
|
_cStringLiterals = [];
|
||||||
|
_stringLiterals = [];
|
||||||
_breakLabels = [];
|
_breakLabels = [];
|
||||||
_continueLabels = [];
|
_continueLabels = [];
|
||||||
_anonymousFunctions = [];
|
_anonymousFunctions = [];
|
||||||
@@ -43,6 +46,7 @@ public static class QBEGenerator
|
|||||||
_labelIndex = 0;
|
_labelIndex = 0;
|
||||||
_anonymousFuncIndex = 0;
|
_anonymousFuncIndex = 0;
|
||||||
_cStringLiteralIndex = 0;
|
_cStringLiteralIndex = 0;
|
||||||
|
_stringLiteralIndex = 0;
|
||||||
_codeIsReachable = true;
|
_codeIsReachable = true;
|
||||||
|
|
||||||
foreach (var structDef in _definitionTable.GetStructs())
|
foreach (var structDef in _definitionTable.GetStructs())
|
||||||
@@ -68,6 +72,12 @@ public static class QBEGenerator
|
|||||||
_builder.AppendLine($"data {cStringLiteral.Name} = {{ b \"{cStringLiteral.Value}\", b 0 }}");
|
_builder.AppendLine($"data {cStringLiteral.Name} = {{ b \"{cStringLiteral.Value}\", b 0 }}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (var stringLiteral in _stringLiterals)
|
||||||
|
{
|
||||||
|
var bytes = Encoding.UTF8.GetBytes(stringLiteral.Value).Select(b => $"b {b}");
|
||||||
|
_builder.AppendLine($"data {stringLiteral.Name} = {{ l {stringLiteral.Value.Length}, {string.Join(", ", bytes)} }}");
|
||||||
|
}
|
||||||
|
|
||||||
return _builder.ToString();
|
return _builder.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,6 +96,11 @@ public static class QBEGenerator
|
|||||||
return $"$cstring{++_cStringLiteralIndex}";
|
return $"$cstring{++_cStringLiteralIndex}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string StringName()
|
||||||
|
{
|
||||||
|
return $"$string{++_stringLiteralIndex}";
|
||||||
|
}
|
||||||
|
|
||||||
private static string FuncName(BoundFuncDefinition funcDef)
|
private static string FuncName(BoundFuncDefinition funcDef)
|
||||||
{
|
{
|
||||||
return funcDef switch
|
return funcDef switch
|
||||||
@@ -128,6 +143,7 @@ public static class QBEGenerator
|
|||||||
NubFixedArrayType => "storel",
|
NubFixedArrayType => "storel",
|
||||||
NubFuncType => "storel",
|
NubFuncType => "storel",
|
||||||
NubCStringType => "storel",
|
NubCStringType => "storel",
|
||||||
|
NubStringType => "storel",
|
||||||
_ => throw new NotSupportedException($"'{type}' type cannot be used in store instructions")
|
_ => throw new NotSupportedException($"'{type}' type cannot be used in store instructions")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -157,6 +173,7 @@ public static class QBEGenerator
|
|||||||
NubFixedArrayType => "loadl",
|
NubFixedArrayType => "loadl",
|
||||||
NubFuncType => "loadl",
|
NubFuncType => "loadl",
|
||||||
NubCStringType => "loadl",
|
NubCStringType => "loadl",
|
||||||
|
NubStringType => "loadl",
|
||||||
_ => throw new NotSupportedException($"'{type}' type cannot be used in load instructions")
|
_ => throw new NotSupportedException($"'{type}' type cannot be used in load instructions")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -186,6 +203,7 @@ public static class QBEGenerator
|
|||||||
NubFixedArrayType => "=l",
|
NubFixedArrayType => "=l",
|
||||||
NubFuncType => "=l",
|
NubFuncType => "=l",
|
||||||
NubCStringType => "=l",
|
NubCStringType => "=l",
|
||||||
|
NubStringType => "=l",
|
||||||
_ => throw new NotSupportedException($"'{type}' type cannot be used in variables")
|
_ => throw new NotSupportedException($"'{type}' type cannot be used in variables")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -213,6 +231,7 @@ public static class QBEGenerator
|
|||||||
case NubPointerType:
|
case NubPointerType:
|
||||||
case NubArrayType:
|
case NubArrayType:
|
||||||
case NubCStringType:
|
case NubCStringType:
|
||||||
|
case NubStringType:
|
||||||
case NubFuncType:
|
case NubFuncType:
|
||||||
{
|
{
|
||||||
return 8;
|
return 8;
|
||||||
@@ -241,12 +260,10 @@ public static class QBEGenerator
|
|||||||
{
|
{
|
||||||
return primitiveType.Kind switch
|
return primitiveType.Kind switch
|
||||||
{
|
{
|
||||||
PrimitiveTypeKind.I64 or PrimitiveTypeKind.U64 => 8,
|
PrimitiveTypeKind.I64 or PrimitiveTypeKind.U64 or PrimitiveTypeKind.F64 => 8,
|
||||||
PrimitiveTypeKind.I32 or PrimitiveTypeKind.U32 or PrimitiveTypeKind.Bool => 4,
|
PrimitiveTypeKind.I32 or PrimitiveTypeKind.U32 or PrimitiveTypeKind.F32 or PrimitiveTypeKind.Bool => 4,
|
||||||
PrimitiveTypeKind.I16 or PrimitiveTypeKind.U16 => 2,
|
PrimitiveTypeKind.I16 or PrimitiveTypeKind.U16 => 2,
|
||||||
PrimitiveTypeKind.I8 or PrimitiveTypeKind.U8 => 1,
|
PrimitiveTypeKind.I8 or PrimitiveTypeKind.U8 => 1,
|
||||||
PrimitiveTypeKind.F64 => 8,
|
|
||||||
PrimitiveTypeKind.F32 => 4,
|
|
||||||
_ => throw new ArgumentOutOfRangeException()
|
_ => throw new ArgumentOutOfRangeException()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -273,6 +290,7 @@ public static class QBEGenerator
|
|||||||
case NubPointerType:
|
case NubPointerType:
|
||||||
case NubArrayType:
|
case NubArrayType:
|
||||||
case NubCStringType:
|
case NubCStringType:
|
||||||
|
case NubStringType:
|
||||||
case NubFuncType:
|
case NubFuncType:
|
||||||
{
|
{
|
||||||
return 8;
|
return 8;
|
||||||
@@ -354,6 +372,7 @@ public static class QBEGenerator
|
|||||||
NubFixedArrayType => "l",
|
NubFixedArrayType => "l",
|
||||||
NubFuncType => "l",
|
NubFuncType => "l",
|
||||||
NubCStringType => "l",
|
NubCStringType => "l",
|
||||||
|
NubStringType => "l",
|
||||||
_ => throw new NotSupportedException($"'{returnType}' type cannot be used as a function return type")
|
_ => throw new NotSupportedException($"'{returnType}' type cannot be used as a function return type")
|
||||||
});
|
});
|
||||||
_builder.Append(' ');
|
_builder.Append(' ');
|
||||||
@@ -386,6 +405,7 @@ public static class QBEGenerator
|
|||||||
NubFixedArrayType => "l",
|
NubFixedArrayType => "l",
|
||||||
NubFuncType => "l",
|
NubFuncType => "l",
|
||||||
NubCStringType => "l",
|
NubCStringType => "l",
|
||||||
|
NubStringType => "l",
|
||||||
_ => throw new NotSupportedException($"'{parameter.Type}' type cannot be used as a function parameter type")
|
_ => throw new NotSupportedException($"'{parameter.Type}' type cannot be used as a function parameter type")
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -424,7 +444,7 @@ public static class QBEGenerator
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
parameterVars.Add(new Variable(parameter.Name, new Val(parameterName, parameter.Type)));
|
parameterVars.Add(new Variable(parameter.Name, new Val(parameterName, parameter.Type, ValKind.Immediate)));
|
||||||
}
|
}
|
||||||
|
|
||||||
EmitBlock(body, parameterVars);
|
EmitBlock(body, parameterVars);
|
||||||
@@ -468,6 +488,7 @@ public static class QBEGenerator
|
|||||||
NubFixedArrayType fixedArrayType => $"b {SizeOf(fixedArrayType)}",
|
NubFixedArrayType fixedArrayType => $"b {SizeOf(fixedArrayType)}",
|
||||||
NubFuncType => "l",
|
NubFuncType => "l",
|
||||||
NubCStringType => "l",
|
NubCStringType => "l",
|
||||||
|
NubStringType => "l",
|
||||||
_ => throw new NotSupportedException($"'{structDefinitionField.Type}' type cannot be used in structs")
|
_ => throw new NotSupportedException($"'{structDefinitionField.Type}' type cannot be used in structs")
|
||||||
};
|
};
|
||||||
_builder.Append(qbeType + ", ");
|
_builder.Append(qbeType + ", ");
|
||||||
@@ -657,7 +678,7 @@ public static class QBEGenerator
|
|||||||
{
|
{
|
||||||
var tmp = VarName();
|
var tmp = VarName();
|
||||||
_builder.AppendLine($" {tmp} =l alloc8 {SizeOf(variableDeclaration.Type)}");
|
_builder.AppendLine($" {tmp} =l alloc8 {SizeOf(variableDeclaration.Type)}");
|
||||||
_variables.Push(new Variable(variableDeclaration.Name, new Val(tmp, variableDeclaration.Type)));
|
_variables.Push(new Variable(variableDeclaration.Name, new Val(tmp, variableDeclaration.Type, ValKind.Pointer)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void EmitVariableAssignment(BoundVariableAssignmentNode variableAssignment)
|
private static void EmitVariableAssignment(BoundVariableAssignmentNode variableAssignment)
|
||||||
@@ -741,7 +762,7 @@ public static class QBEGenerator
|
|||||||
var pointer = EmitArrayIndexPointer(arrayIndexAccess);
|
var pointer = EmitArrayIndexPointer(arrayIndexAccess);
|
||||||
var outputName = VarName();
|
var outputName = VarName();
|
||||||
_builder.AppendLine($" {outputName} {QBEAssign(arrayIndexAccess.Type)} {QBELoad(arrayIndexAccess.Type)} {pointer}");
|
_builder.AppendLine($" {outputName} {QBEAssign(arrayIndexAccess.Type)} {QBELoad(arrayIndexAccess.Type)} {pointer}");
|
||||||
return new Val(outputName, arrayIndexAccess.Type);
|
return new Val(outputName, arrayIndexAccess.Type, ValKind.Immediate);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void EmitArrayBoundsCheck(string array, string index)
|
private static void EmitArrayBoundsCheck(string array, string index)
|
||||||
@@ -786,7 +807,7 @@ public static class QBEGenerator
|
|||||||
_builder.AppendLine($" {dataPointer} =l add {arrayPointer}, 8");
|
_builder.AppendLine($" {dataPointer} =l add {arrayPointer}, 8");
|
||||||
_builder.AppendLine($" call $nub_memset(l {dataPointer}, w 0, l {capacityInBytes})");
|
_builder.AppendLine($" call $nub_memset(l {dataPointer}, w 0, l {capacityInBytes})");
|
||||||
|
|
||||||
return new Val(arrayPointer, arrayInitializer.Type);
|
return new Val(arrayPointer, arrayInitializer.Type, ValKind.Immediate);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Val EmitDereference(BoundDereferenceNode dereference)
|
private static Val EmitDereference(BoundDereferenceNode dereference)
|
||||||
@@ -794,7 +815,7 @@ public static class QBEGenerator
|
|||||||
var result = EmitUnwrap(EmitExpression(dereference.Expression));
|
var result = EmitUnwrap(EmitExpression(dereference.Expression));
|
||||||
var outputName = VarName();
|
var outputName = VarName();
|
||||||
_builder.AppendLine($" {outputName} {QBEAssign(dereference.Type)} {QBELoad(dereference.Type)} {result}");
|
_builder.AppendLine($" {outputName} {QBEAssign(dereference.Type)} {QBELoad(dereference.Type)} {result}");
|
||||||
return new Val(outputName, dereference.Type);
|
return new Val(outputName, dereference.Type, ValKind.Immediate);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Val EmitAddressOf(BoundAddressOfNode addressOf)
|
private static Val EmitAddressOf(BoundAddressOfNode addressOf)
|
||||||
@@ -802,22 +823,27 @@ public static class QBEGenerator
|
|||||||
switch (addressOf.Expression)
|
switch (addressOf.Expression)
|
||||||
{
|
{
|
||||||
case BoundArrayIndexAccessNode arrayIndexAccess:
|
case BoundArrayIndexAccessNode arrayIndexAccess:
|
||||||
|
{
|
||||||
var pointer = EmitArrayIndexPointer(arrayIndexAccess);
|
var pointer = EmitArrayIndexPointer(arrayIndexAccess);
|
||||||
return new Val(pointer, addressOf.Type);
|
return new Val(pointer, addressOf.Type, ValKind.Immediate);
|
||||||
|
}
|
||||||
case BoundDereferenceNode dereference:
|
case BoundDereferenceNode dereference:
|
||||||
|
{
|
||||||
return EmitExpression(dereference.Expression);
|
return EmitExpression(dereference.Expression);
|
||||||
|
}
|
||||||
case BoundIdentifierNode identifier:
|
case BoundIdentifierNode identifier:
|
||||||
|
{
|
||||||
if (identifier.Namespace.HasValue)
|
if (identifier.Namespace.HasValue)
|
||||||
{
|
{
|
||||||
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).Val;
|
return _variables.Single(x => x.Name == identifier.Name).Val;
|
||||||
case BoundMemberAccessNode memberAccess:
|
}
|
||||||
var ptr = EmitMemberAccessPointer(memberAccess);
|
|
||||||
return new Val(ptr, addressOf.Type);
|
|
||||||
default:
|
default:
|
||||||
|
{
|
||||||
throw new ArgumentOutOfRangeException();
|
throw new ArgumentOutOfRangeException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -826,7 +852,7 @@ public static class QBEGenerator
|
|||||||
var left = EmitUnwrap(EmitExpression(binaryExpression.Left));
|
var left = EmitUnwrap(EmitExpression(binaryExpression.Left));
|
||||||
var right = EmitUnwrap(EmitExpression(binaryExpression.Right));
|
var right = EmitUnwrap(EmitExpression(binaryExpression.Right));
|
||||||
var outputName = VarName();
|
var outputName = VarName();
|
||||||
var output = new Val(outputName, binaryExpression.Type);
|
var output = new Val(outputName, binaryExpression.Type, ValKind.Immediate);
|
||||||
|
|
||||||
switch (binaryExpression.Operator)
|
switch (binaryExpression.Operator)
|
||||||
{
|
{
|
||||||
@@ -1052,44 +1078,80 @@ public static class QBEGenerator
|
|||||||
|
|
||||||
private static Val EmitLiteral(BoundLiteralNode literal)
|
private static Val EmitLiteral(BoundLiteralNode literal)
|
||||||
{
|
{
|
||||||
if (literal.Type.IsInteger)
|
|
||||||
{
|
|
||||||
switch (literal.Kind)
|
|
||||||
{
|
|
||||||
case LiteralKind.Integer:
|
|
||||||
return new Val(literal.Literal, literal.Type, ValKind.Literal);
|
|
||||||
case LiteralKind.Float:
|
|
||||||
return new Val(literal.Literal.Split(".").First(), literal.Type, ValKind.Literal);
|
|
||||||
default:
|
|
||||||
throw new ArgumentOutOfRangeException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (literal.Type.IsFloat64)
|
|
||||||
{
|
|
||||||
var value = double.Parse(literal.Literal, CultureInfo.InvariantCulture);
|
|
||||||
var bits = BitConverter.DoubleToInt64Bits(value);
|
|
||||||
return new Val(bits.ToString(), literal.Type, ValKind.Literal);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (literal.Type.IsFloat32)
|
|
||||||
{
|
|
||||||
var value = float.Parse(literal.Literal, CultureInfo.InvariantCulture);
|
|
||||||
var bits = BitConverter.SingleToInt32Bits(value);
|
|
||||||
return new Val(bits.ToString(), literal.Type, ValKind.Literal);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (literal.Kind)
|
switch (literal.Kind)
|
||||||
{
|
{
|
||||||
|
case LiteralKind.Integer:
|
||||||
|
{
|
||||||
|
if (literal.Type.IsFloat32)
|
||||||
|
{
|
||||||
|
var value = float.Parse(literal.Literal, CultureInfo.InvariantCulture);
|
||||||
|
var bits = BitConverter.SingleToInt32Bits(value);
|
||||||
|
return new Val(bits.ToString(), literal.Type, ValKind.Immediate);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (literal.Type.IsFloat64)
|
||||||
|
{
|
||||||
|
var value = double.Parse(literal.Literal, CultureInfo.InvariantCulture);
|
||||||
|
var bits = BitConverter.DoubleToInt64Bits(value);
|
||||||
|
return new Val(bits.ToString(), literal.Type, ValKind.Immediate);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (literal.Type.IsInteger)
|
||||||
|
{
|
||||||
|
return new Val(literal.Literal, literal.Type, ValKind.Immediate);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case LiteralKind.Float:
|
||||||
|
{
|
||||||
|
if (literal.Type.IsInteger)
|
||||||
|
{
|
||||||
|
return new Val(literal.Literal.Split(".").First(), literal.Type, ValKind.Immediate);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (literal.Type.IsFloat32)
|
||||||
|
{
|
||||||
|
var value = float.Parse(literal.Literal, CultureInfo.InvariantCulture);
|
||||||
|
var bits = BitConverter.SingleToInt32Bits(value);
|
||||||
|
return new Val(bits.ToString(), literal.Type, ValKind.Immediate);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (literal.Type.IsFloat64)
|
||||||
|
{
|
||||||
|
var value = double.Parse(literal.Literal, CultureInfo.InvariantCulture);
|
||||||
|
var bits = BitConverter.DoubleToInt64Bits(value);
|
||||||
|
return new Val(bits.ToString(), literal.Type, ValKind.Immediate);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case LiteralKind.String:
|
case LiteralKind.String:
|
||||||
var cStringLiteral = new CStringLiteral(literal.Literal, CStringName());
|
{
|
||||||
_cStringLiterals.Add(cStringLiteral);
|
if (literal.Type.IsString)
|
||||||
return new Val(cStringLiteral.Name, literal.Type, ValKind.Literal);
|
{
|
||||||
|
var stringLiteral = new StringLiteral(literal.Literal, StringName());
|
||||||
|
_stringLiterals.Add(stringLiteral);
|
||||||
|
return new Val(stringLiteral.Name, literal.Type, ValKind.Immediate);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (literal.Type.IsCString)
|
||||||
|
{
|
||||||
|
var cStringLiteral = new CStringLiteral(literal.Literal, CStringName());
|
||||||
|
_cStringLiterals.Add(cStringLiteral);
|
||||||
|
return new Val(cStringLiteral.Name, literal.Type, ValKind.Immediate);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case LiteralKind.Bool:
|
case LiteralKind.Bool:
|
||||||
return new Val(bool.Parse(literal.Literal) ? "1" : "0", literal.Type, ValKind.Literal);
|
{
|
||||||
default:
|
if (literal.Type.IsBool)
|
||||||
throw new ArgumentOutOfRangeException();
|
{
|
||||||
|
return new Val(bool.Parse(literal.Literal) ? "1" : "0", literal.Type, ValKind.Immediate);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
throw new NotSupportedException($"Cannot create literal of kind '{literal.Kind}' for type {literal.Type}");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Val EmitStructInitializer(BoundStructInitializerNode structInitializer)
|
private static Val EmitStructInitializer(BoundStructInitializerNode structInitializer)
|
||||||
@@ -1124,7 +1186,7 @@ public static class QBEGenerator
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Val(output, structInitializer.StructType);
|
return new Val(output, structInitializer.StructType, ValKind.Immediate);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Val EmitUnaryExpression(BoundUnaryExpressionNode unaryExpression)
|
private static Val EmitUnaryExpression(BoundUnaryExpressionNode unaryExpression)
|
||||||
@@ -1140,16 +1202,16 @@ public static class QBEGenerator
|
|||||||
{
|
{
|
||||||
case NubPrimitiveType { Kind: PrimitiveTypeKind.I64 }:
|
case NubPrimitiveType { Kind: PrimitiveTypeKind.I64 }:
|
||||||
_builder.AppendLine($" {outputName} =l neg {operand}");
|
_builder.AppendLine($" {outputName} =l neg {operand}");
|
||||||
return new Val(outputName, unaryExpression.Type);
|
return new Val(outputName, unaryExpression.Type, ValKind.Immediate);
|
||||||
case NubPrimitiveType { Kind: PrimitiveTypeKind.I32 or PrimitiveTypeKind.I16 or PrimitiveTypeKind.I8 }:
|
case NubPrimitiveType { Kind: PrimitiveTypeKind.I32 or PrimitiveTypeKind.I16 or PrimitiveTypeKind.I8 }:
|
||||||
_builder.AppendLine($" {outputName} =w neg {operand}");
|
_builder.AppendLine($" {outputName} =w neg {operand}");
|
||||||
return new Val(outputName, unaryExpression.Type);
|
return new Val(outputName, unaryExpression.Type, ValKind.Immediate);
|
||||||
case NubPrimitiveType { Kind: PrimitiveTypeKind.F64 }:
|
case NubPrimitiveType { Kind: PrimitiveTypeKind.F64 }:
|
||||||
_builder.AppendLine($" {outputName} =d neg {operand}");
|
_builder.AppendLine($" {outputName} =d neg {operand}");
|
||||||
return new Val(outputName, unaryExpression.Type);
|
return new Val(outputName, unaryExpression.Type, ValKind.Immediate);
|
||||||
case NubPrimitiveType { Kind: PrimitiveTypeKind.F32 }:
|
case NubPrimitiveType { Kind: PrimitiveTypeKind.F32 }:
|
||||||
_builder.AppendLine($" {outputName} =s neg {operand}");
|
_builder.AppendLine($" {outputName} =s neg {operand}");
|
||||||
return new Val(outputName, unaryExpression.Type);
|
return new Val(outputName, unaryExpression.Type, ValKind.Immediate);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -1160,7 +1222,7 @@ public static class QBEGenerator
|
|||||||
{
|
{
|
||||||
case NubPrimitiveType { Kind: PrimitiveTypeKind.Bool }:
|
case NubPrimitiveType { Kind: PrimitiveTypeKind.Bool }:
|
||||||
_builder.AppendLine($" {outputName} =w xor {operand}, 1");
|
_builder.AppendLine($" {outputName} =w xor {operand}, 1");
|
||||||
return new Val(outputName, unaryExpression.Type);
|
return new Val(outputName, unaryExpression.Type, ValKind.Immediate);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -1174,43 +1236,50 @@ public static class QBEGenerator
|
|||||||
throw new NotSupportedException($"Unary operator {unaryExpression.Operator} for type {unaryExpression.Operand.Type} not supported");
|
throw new NotSupportedException($"Unary operator {unaryExpression.Operator} for type {unaryExpression.Operand.Type} not supported");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string EmitMemberAccessPointer(BoundMemberAccessNode memberAccess)
|
private static Val EmitMemberAccess(BoundMemberAccessNode memberAccess)
|
||||||
{
|
{
|
||||||
var item = EmitUnwrap(EmitExpression(memberAccess.Expression));
|
var item = EmitUnwrap(EmitExpression(memberAccess.Expression));
|
||||||
|
var output = VarName();
|
||||||
|
|
||||||
switch (memberAccess.Expression.Type)
|
switch (memberAccess.Expression.Type)
|
||||||
{
|
{
|
||||||
case NubArrayType:
|
case NubArrayType:
|
||||||
{
|
{
|
||||||
if (memberAccess.Member == "count")
|
if (memberAccess.Member == "count")
|
||||||
{
|
{
|
||||||
return item;
|
_builder.AppendLine($" {output} =l loadl {item}");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new UnreachableException(nameof(memberAccess.Member));
|
throw new UnreachableException();
|
||||||
|
}
|
||||||
|
case NubStringType:
|
||||||
|
{
|
||||||
|
_builder.AppendLine($" {output} =l call $nub_string_length(l {item})");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case NubCStringType:
|
||||||
|
{
|
||||||
|
_builder.AppendLine($" {output} =l call $nub_cstring_length(l {item})");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
case NubStructType structType:
|
case NubStructType structType:
|
||||||
{
|
{
|
||||||
var structDefinition = _definitionTable.LookupStruct(structType.Namespace, structType.Name).GetValue();
|
var structDefinition = _definitionTable.LookupStruct(structType.Namespace, structType.Name).GetValue();
|
||||||
var offset = OffsetOf(structDefinition, memberAccess.Member);
|
var offset = OffsetOf(structDefinition, memberAccess.Member);
|
||||||
|
|
||||||
var offsetName = VarName();
|
var offsetName = VarName();
|
||||||
_builder.AppendLine($" {offsetName} =l add {item}, {offset}");
|
_builder.AppendLine($" {offsetName} =l add {item}, {offset}");
|
||||||
return offsetName;
|
_builder.AppendLine($" {output} {QBEAssign(memberAccess.Type)} {QBELoad(memberAccess.Type)} {item}");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
throw new ArgumentOutOfRangeException(nameof(memberAccess.Expression.Type));
|
throw new ArgumentOutOfRangeException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
return new Val(output, memberAccess.Type, ValKind.Immediate);
|
||||||
private static Val EmitMemberAccess(BoundMemberAccessNode memberAccess)
|
|
||||||
{
|
|
||||||
var pointer = EmitMemberAccessPointer(memberAccess);
|
|
||||||
|
|
||||||
var output = VarName();
|
|
||||||
_builder.AppendLine($" {output} {QBEAssign(memberAccess.Type)} {QBELoad(memberAccess.Type)} {pointer}");
|
|
||||||
return new Val(output, memberAccess.Type);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Val EmitFixedArrayInitializer(BoundFixedArrayInitializerNode fixedArrayInitializer)
|
private static Val EmitFixedArrayInitializer(BoundFixedArrayInitializerNode fixedArrayInitializer)
|
||||||
@@ -1227,7 +1296,7 @@ public static class QBEGenerator
|
|||||||
var dataSize = totalSize - 8;
|
var dataSize = totalSize - 8;
|
||||||
_builder.AppendLine($" call $nub_memset(l {dataPtr}, w 0, l {dataSize})");
|
_builder.AppendLine($" call $nub_memset(l {dataPtr}, w 0, l {dataSize})");
|
||||||
|
|
||||||
return new Val(outputName, fixedArrayInitializer.Type);
|
return new Val(outputName, fixedArrayInitializer.Type, ValKind.Immediate);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Val EmitFuncCall(BoundFuncCallNode funcCall)
|
private static Val EmitFuncCall(BoundFuncCallNode funcCall)
|
||||||
@@ -1264,6 +1333,7 @@ public static class QBEGenerator
|
|||||||
NubFixedArrayType => "l",
|
NubFixedArrayType => "l",
|
||||||
NubFuncType => "l",
|
NubFuncType => "l",
|
||||||
NubCStringType => "l",
|
NubCStringType => "l",
|
||||||
|
NubStringType => "l",
|
||||||
_ => throw new NotSupportedException($"'{parameter.Type}' type cannot be used in function calls")
|
_ => throw new NotSupportedException($"'{parameter.Type}' type cannot be used in function calls")
|
||||||
};
|
};
|
||||||
parameterStrings.Add($"{qbeType} {result}");
|
parameterStrings.Add($"{qbeType} {result}");
|
||||||
@@ -1275,12 +1345,12 @@ public static class QBEGenerator
|
|||||||
{
|
{
|
||||||
var outputName = VarName();
|
var outputName = VarName();
|
||||||
_builder.AppendLine($" {outputName} {QBEAssign(funcCall.Type)} call {funcPointer}({string.Join(", ", parameterStrings)})");
|
_builder.AppendLine($" {outputName} {QBEAssign(funcCall.Type)} call {funcPointer}({string.Join(", ", parameterStrings)})");
|
||||||
return new Val(outputName, funcCall.Type);
|
return new Val(outputName, funcCall.Type, ValKind.Immediate);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_builder.AppendLine($" call {funcPointer}({string.Join(", ", parameterStrings)})");
|
_builder.AppendLine($" call {funcPointer}({string.Join(", ", parameterStrings)})");
|
||||||
return new Val(string.Empty, funcCall.Type);
|
return new Val(string.Empty, funcCall.Type, ValKind.Immediate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1306,9 +1376,9 @@ public static class QBEGenerator
|
|||||||
switch (val.Kind)
|
switch (val.Kind)
|
||||||
{
|
{
|
||||||
case ValKind.Func:
|
case ValKind.Func:
|
||||||
case ValKind.Literal:
|
case ValKind.Immediate:
|
||||||
return val.Name;
|
return val.Name;
|
||||||
case ValKind.Variable:
|
case ValKind.Pointer:
|
||||||
if (IsPointerType(val.Type))
|
if (IsPointerType(val.Type))
|
||||||
{
|
{
|
||||||
return val.Name;
|
return val.Name;
|
||||||
@@ -1325,6 +1395,12 @@ public static class QBEGenerator
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal class StringLiteral(string value, string name)
|
||||||
|
{
|
||||||
|
public string Value { get; } = value;
|
||||||
|
public string Name { get; } = name;
|
||||||
|
}
|
||||||
|
|
||||||
internal class CStringLiteral(string value, string name)
|
internal class CStringLiteral(string value, string name)
|
||||||
{
|
{
|
||||||
public string Value { get; } = value;
|
public string Value { get; } = value;
|
||||||
@@ -1337,7 +1413,7 @@ internal class Variable(string name, Val val)
|
|||||||
public Val Val { get; } = val;
|
public Val Val { get; } = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class Val(string name, NubType type, ValKind kind = ValKind.Variable)
|
internal class Val(string name, NubType type, ValKind kind)
|
||||||
{
|
{
|
||||||
public string Name { get; } = name;
|
public string Name { get; } = name;
|
||||||
public NubType Type { get; } = type;
|
public NubType Type { get; } = type;
|
||||||
@@ -1352,6 +1428,6 @@ internal class Val(string name, NubType type, ValKind kind = ValKind.Variable)
|
|||||||
internal enum ValKind
|
internal enum ValKind
|
||||||
{
|
{
|
||||||
Func,
|
Func,
|
||||||
Variable,
|
Pointer,
|
||||||
Literal
|
Immediate
|
||||||
}
|
}
|
||||||
@@ -39,6 +39,6 @@ public record AnonymousFuncNode(IEnumerable<Token> Tokens, List<FuncParameter> P
|
|||||||
public record AddressOfNode(IEnumerable<Token> Tokens, LValueNode Expression) : ExpressionNode(Tokens);
|
public record AddressOfNode(IEnumerable<Token> Tokens, LValueNode Expression) : ExpressionNode(Tokens);
|
||||||
public record FixedArrayInitializerNode(IEnumerable<Token> Tokens, NubType ElementType, int Capacity) : ExpressionNode(Tokens);
|
public record FixedArrayInitializerNode(IEnumerable<Token> Tokens, NubType ElementType, int Capacity) : ExpressionNode(Tokens);
|
||||||
public record LiteralNode(IEnumerable<Token> Tokens, string Literal, LiteralKind Kind) : ExpressionNode(Tokens);
|
public record LiteralNode(IEnumerable<Token> Tokens, string Literal, LiteralKind Kind) : ExpressionNode(Tokens);
|
||||||
public record MemberAccessNode(IEnumerable<Token> Tokens, ExpressionNode Expression, string Member) : LValueNode(Tokens);
|
public record MemberAccessNode(IEnumerable<Token> Tokens, ExpressionNode Expression, string Member) : ExpressionNode(Tokens);
|
||||||
public record StructInitializerNode(IEnumerable<Token> Tokens, NubStructType StructType, Dictionary<string, ExpressionNode> Initializers) : ExpressionNode(Tokens);
|
public record StructInitializerNode(IEnumerable<Token> Tokens, NubStructType StructType, Dictionary<string, ExpressionNode> Initializers) : ExpressionNode(Tokens);
|
||||||
public record DereferenceNode(IEnumerable<Token> Tokens, ExpressionNode Expression) : LValueNode(Tokens);
|
public record DereferenceNode(IEnumerable<Token> Tokens, ExpressionNode Expression) : LValueNode(Tokens);
|
||||||
|
|||||||
@@ -668,7 +668,7 @@ public static class Parser
|
|||||||
|
|
||||||
if (name.Value == "string")
|
if (name.Value == "string")
|
||||||
{
|
{
|
||||||
return new NubArrayType(NubPrimitiveType.U8);
|
return new NubStringType();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (name.Value == "cstring")
|
if (name.Value == "cstring")
|
||||||
|
|||||||
@@ -347,7 +347,7 @@ public static class Binder
|
|||||||
{
|
{
|
||||||
LiteralKind.Integer => NubPrimitiveType.I64,
|
LiteralKind.Integer => NubPrimitiveType.I64,
|
||||||
LiteralKind.Float => NubPrimitiveType.F64,
|
LiteralKind.Float => NubPrimitiveType.F64,
|
||||||
LiteralKind.String => new NubCStringType(),
|
LiteralKind.String => new NubStringType(),
|
||||||
LiteralKind.Bool => NubPrimitiveType.Bool,
|
LiteralKind.Bool => NubPrimitiveType.Bool,
|
||||||
_ => throw new ArgumentOutOfRangeException()
|
_ => throw new ArgumentOutOfRangeException()
|
||||||
};
|
};
|
||||||
@@ -364,10 +364,12 @@ public static class Binder
|
|||||||
switch (boundExpression.Type)
|
switch (boundExpression.Type)
|
||||||
{
|
{
|
||||||
case NubArrayType:
|
case NubArrayType:
|
||||||
|
case NubStringType:
|
||||||
|
case NubCStringType:
|
||||||
{
|
{
|
||||||
if (expression.Member == "count")
|
if (expression.Member == "count")
|
||||||
{
|
{
|
||||||
type = NubPrimitiveType.I64;
|
type = NubPrimitiveType.U64;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -16,6 +16,6 @@ public record BoundAnonymousFuncNode(IEnumerable<Token> Tokens, NubType Type, Li
|
|||||||
public record BoundAddressOfNode(IEnumerable<Token> Tokens, NubType Type, BoundLValueNode Expression) : BoundExpressionNode(Tokens, Type);
|
public record BoundAddressOfNode(IEnumerable<Token> Tokens, NubType Type, BoundLValueNode Expression) : BoundExpressionNode(Tokens, Type);
|
||||||
public record BoundFixedArrayInitializerNode(IEnumerable<Token> Tokens, NubType Type, NubType ElementType, int Capacity) : BoundExpressionNode(Tokens, Type);
|
public record BoundFixedArrayInitializerNode(IEnumerable<Token> Tokens, NubType Type, NubType ElementType, int Capacity) : BoundExpressionNode(Tokens, Type);
|
||||||
public record BoundLiteralNode(IEnumerable<Token> Tokens, NubType Type, string Literal, LiteralKind Kind) : BoundExpressionNode(Tokens, Type);
|
public record BoundLiteralNode(IEnumerable<Token> Tokens, NubType Type, string Literal, LiteralKind Kind) : BoundExpressionNode(Tokens, Type);
|
||||||
public record BoundMemberAccessNode(IEnumerable<Token> Tokens, NubType Type, BoundExpressionNode Expression, string Member) : BoundLValueNode(Tokens, Type);
|
public record BoundMemberAccessNode(IEnumerable<Token> Tokens, NubType Type, BoundExpressionNode Expression, string Member) : BoundExpressionNode(Tokens, Type);
|
||||||
public record BoundStructInitializerNode(IEnumerable<Token> Tokens, NubType Type, NubStructType StructType, Dictionary<string, BoundExpressionNode> Initializers) : BoundExpressionNode(Tokens, Type);
|
public record BoundStructInitializerNode(IEnumerable<Token> Tokens, NubType Type, NubStructType StructType, Dictionary<string, BoundExpressionNode> Initializers) : BoundExpressionNode(Tokens, Type);
|
||||||
public record BoundDereferenceNode(IEnumerable<Token> Tokens, NubType Type, BoundExpressionNode Expression) : BoundLValueNode(Tokens, Type);
|
public record BoundDereferenceNode(IEnumerable<Token> Tokens, NubType Type, BoundExpressionNode Expression) : BoundLValueNode(Tokens, Type);
|
||||||
|
|||||||
@@ -4,21 +4,6 @@ namespace Syntax.Typing;
|
|||||||
|
|
||||||
public abstract class NubType
|
public abstract class NubType
|
||||||
{
|
{
|
||||||
public static bool IsCompatibleWith(NubType sourceType, NubType targetType)
|
|
||||||
{
|
|
||||||
if (targetType is NubAnyType || sourceType.Equals(targetType))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sourceType is NubFixedArrayType fixedArray && targetType is NubArrayType array && IsCompatibleWith(fixedArray.ElementType, array.ElementType))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsInteger => this is NubPrimitiveType
|
public bool IsInteger => this is NubPrimitiveType
|
||||||
{
|
{
|
||||||
Kind: PrimitiveTypeKind.I8
|
Kind: PrimitiveTypeKind.I8
|
||||||
@@ -45,6 +30,15 @@ public abstract class NubType
|
|||||||
|
|
||||||
public bool IsVoid => this is NubVoidType;
|
public bool IsVoid => this is NubVoidType;
|
||||||
|
|
||||||
|
public bool IsString => this is NubStringType;
|
||||||
|
|
||||||
|
public bool IsCString => this is NubCStringType;
|
||||||
|
|
||||||
|
public bool IsBool => this is NubPrimitiveType
|
||||||
|
{
|
||||||
|
Kind: PrimitiveTypeKind.Bool
|
||||||
|
};
|
||||||
|
|
||||||
public abstract override bool Equals(object? obj);
|
public abstract override bool Equals(object? obj);
|
||||||
public abstract override int GetHashCode();
|
public abstract override int GetHashCode();
|
||||||
public abstract override string ToString();
|
public abstract override string ToString();
|
||||||
@@ -54,7 +48,7 @@ public class NubCStringType : NubType
|
|||||||
{
|
{
|
||||||
public override bool Equals(object? obj)
|
public override bool Equals(object? obj)
|
||||||
{
|
{
|
||||||
return obj is NubCStringType other;
|
return obj is NubCStringType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int GetHashCode()
|
public override int GetHashCode()
|
||||||
@@ -68,6 +62,24 @@ public class NubCStringType : NubType
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class NubStringType : NubType
|
||||||
|
{
|
||||||
|
public override bool Equals(object? obj)
|
||||||
|
{
|
||||||
|
return obj is NubStringType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return "string".GetHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return "string";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public class NubFuncType(NubType returnType, List<NubType> parameters) : NubType
|
public class NubFuncType(NubType returnType, List<NubType> parameters) : NubType
|
||||||
{
|
{
|
||||||
public NubType ReturnType { get; } = returnType;
|
public NubType ReturnType { get; } = returnType;
|
||||||
|
|||||||
Reference in New Issue
Block a user