This commit is contained in:
nub31
2025-06-26 11:50:37 +02:00
parent 493f188be4
commit 3cb8a5b4c9
12 changed files with 255 additions and 193 deletions

View File

@@ -1,4 +1,4 @@
namespace c
// extern func printf(fmt: ^u8, ...args: any): void
extern func printf(fmt: cstring, arg: u64): void
extern func puts(fmt: cstring)

View File

@@ -5,35 +5,39 @@ struct Human {
}
export func main(args: []cstring): i64 {
let human: Human
// let human: Human
human = alloc Human {
name = "member"
}
// human = alloc Human {
// 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
}

View File

@@ -14,13 +14,11 @@
<ProjectReference Include="..\Syntax\Syntax.csproj" />
</ItemGroup>
<ItemGroup>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Runtime\entry.s" />
<EmbeddedResource Include="Runtime\nub_mem.s" />
<EmbeddedResource Include="Runtime\nub_panic.s" />
<EmbeddedResource Include="Runtime\nub_cstring.s" />
<EmbeddedResource Include="Runtime\nub_string.s" />
</ItemGroup>

View 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

View File

@@ -6,6 +6,7 @@
nub_memcpy:
mov rcx, rdx
rep movsb
ret
.text
.globl nub_memset

View File

@@ -1,80 +1,32 @@
.intel_syntax noprefix
.equ SYS_MMAP, 9
.text
.globl nub_strlen
# func nub_strlen(string: cstring): u64
nub_strlen:
test rdi, rdi
jz null_string
xor rax, rax
strlen_loop:
cmp byte ptr [rdi + rax], 0
je strlen_exit
.globl nub_string_length
# func nub_string_length(string: string): u64
nub_string_length:
mov rsi, [rdi] # Length of string in bytes
add rdi, 8 # Start of bytes
xor rax, rax # Character count
xor rdx, rdx # Current byte position
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
jmp strlen_loop
null_string:
xor rax, rax
strlen_exit:
ret
.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
_skip_byte:
inc rdx
jmp _count_loop
_done:
ret

View File

@@ -16,6 +16,7 @@ public static class QBEGenerator
private static StringBuilder _builder = new();
private static List<CStringLiteral> _cStringLiterals = [];
private static List<StringLiteral> _stringLiterals = [];
private static Stack<string> _breakLabels = [];
private static Stack<string> _continueLabels = [];
private static Queue<(BoundAnonymousFuncNode Func, string Name)> _anonymousFunctions = [];
@@ -25,6 +26,7 @@ public static class QBEGenerator
private static int _labelIndex;
private static int _anonymousFuncIndex;
private static int _cStringLiteralIndex;
private static int _stringLiteralIndex;
private static bool _codeIsReachable = true;
public static string Emit(BoundSyntaxTree syntaxTree, BoundDefinitionTable definitionTable)
@@ -34,6 +36,7 @@ public static class QBEGenerator
_builder = new StringBuilder();
_cStringLiterals = [];
_stringLiterals = [];
_breakLabels = [];
_continueLabels = [];
_anonymousFunctions = [];
@@ -43,6 +46,7 @@ public static class QBEGenerator
_labelIndex = 0;
_anonymousFuncIndex = 0;
_cStringLiteralIndex = 0;
_stringLiteralIndex = 0;
_codeIsReachable = true;
foreach (var structDef in _definitionTable.GetStructs())
@@ -68,6 +72,12 @@ public static class QBEGenerator
_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();
}
@@ -86,6 +96,11 @@ public static class QBEGenerator
return $"$cstring{++_cStringLiteralIndex}";
}
private static string StringName()
{
return $"$string{++_stringLiteralIndex}";
}
private static string FuncName(BoundFuncDefinition funcDef)
{
return funcDef switch
@@ -128,6 +143,7 @@ public static class QBEGenerator
NubFixedArrayType => "storel",
NubFuncType => "storel",
NubCStringType => "storel",
NubStringType => "storel",
_ => throw new NotSupportedException($"'{type}' type cannot be used in store instructions")
};
}
@@ -157,6 +173,7 @@ public static class QBEGenerator
NubFixedArrayType => "loadl",
NubFuncType => "loadl",
NubCStringType => "loadl",
NubStringType => "loadl",
_ => throw new NotSupportedException($"'{type}' type cannot be used in load instructions")
};
}
@@ -186,6 +203,7 @@ public static class QBEGenerator
NubFixedArrayType => "=l",
NubFuncType => "=l",
NubCStringType => "=l",
NubStringType => "=l",
_ => throw new NotSupportedException($"'{type}' type cannot be used in variables")
};
}
@@ -213,6 +231,7 @@ public static class QBEGenerator
case NubPointerType:
case NubArrayType:
case NubCStringType:
case NubStringType:
case NubFuncType:
{
return 8;
@@ -241,12 +260,10 @@ public static class QBEGenerator
{
return primitiveType.Kind switch
{
PrimitiveTypeKind.I64 or PrimitiveTypeKind.U64 => 8,
PrimitiveTypeKind.I32 or PrimitiveTypeKind.U32 or PrimitiveTypeKind.Bool => 4,
PrimitiveTypeKind.I64 or PrimitiveTypeKind.U64 or PrimitiveTypeKind.F64 => 8,
PrimitiveTypeKind.I32 or PrimitiveTypeKind.U32 or PrimitiveTypeKind.F32 or PrimitiveTypeKind.Bool => 4,
PrimitiveTypeKind.I16 or PrimitiveTypeKind.U16 => 2,
PrimitiveTypeKind.I8 or PrimitiveTypeKind.U8 => 1,
PrimitiveTypeKind.F64 => 8,
PrimitiveTypeKind.F32 => 4,
_ => throw new ArgumentOutOfRangeException()
};
}
@@ -273,6 +290,7 @@ public static class QBEGenerator
case NubPointerType:
case NubArrayType:
case NubCStringType:
case NubStringType:
case NubFuncType:
{
return 8;
@@ -354,6 +372,7 @@ public static class QBEGenerator
NubFixedArrayType => "l",
NubFuncType => "l",
NubCStringType => "l",
NubStringType => "l",
_ => throw new NotSupportedException($"'{returnType}' type cannot be used as a function return type")
});
_builder.Append(' ');
@@ -386,6 +405,7 @@ public static class QBEGenerator
NubFixedArrayType => "l",
NubFuncType => "l",
NubCStringType => "l",
NubStringType => "l",
_ => 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);
@@ -468,6 +488,7 @@ public static class QBEGenerator
NubFixedArrayType fixedArrayType => $"b {SizeOf(fixedArrayType)}",
NubFuncType => "l",
NubCStringType => "l",
NubStringType => "l",
_ => throw new NotSupportedException($"'{structDefinitionField.Type}' type cannot be used in structs")
};
_builder.Append(qbeType + ", ");
@@ -657,7 +678,7 @@ public static class QBEGenerator
{
var tmp = VarName();
_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)
@@ -741,7 +762,7 @@ public static class QBEGenerator
var pointer = EmitArrayIndexPointer(arrayIndexAccess);
var outputName = VarName();
_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)
@@ -786,7 +807,7 @@ public static class QBEGenerator
_builder.AppendLine($" {dataPointer} =l add {arrayPointer}, 8");
_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)
@@ -794,7 +815,7 @@ public static class QBEGenerator
var result = EmitUnwrap(EmitExpression(dereference.Expression));
var outputName = VarName();
_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)
@@ -802,22 +823,27 @@ public static class QBEGenerator
switch (addressOf.Expression)
{
case BoundArrayIndexAccessNode arrayIndexAccess:
{
var pointer = EmitArrayIndexPointer(arrayIndexAccess);
return new Val(pointer, addressOf.Type);
return new Val(pointer, addressOf.Type, ValKind.Immediate);
}
case BoundDereferenceNode dereference:
{
return EmitExpression(dereference.Expression);
}
case BoundIdentifierNode identifier:
{
if (identifier.Namespace.HasValue)
{
throw new NotSupportedException("There is nothing to address in another namespace");
}
return _variables.Single(x => x.Name == identifier.Name).Val;
case BoundMemberAccessNode memberAccess:
var ptr = EmitMemberAccessPointer(memberAccess);
return new Val(ptr, addressOf.Type);
}
default:
{
throw new ArgumentOutOfRangeException();
}
}
}
@@ -826,7 +852,7 @@ public static class QBEGenerator
var left = EmitUnwrap(EmitExpression(binaryExpression.Left));
var right = EmitUnwrap(EmitExpression(binaryExpression.Right));
var outputName = VarName();
var output = new Val(outputName, binaryExpression.Type);
var output = new Val(outputName, binaryExpression.Type, ValKind.Immediate);
switch (binaryExpression.Operator)
{
@@ -1052,44 +1078,80 @@ public static class QBEGenerator
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)
{
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:
var cStringLiteral = new CStringLiteral(literal.Literal, CStringName());
_cStringLiterals.Add(cStringLiteral);
return new Val(cStringLiteral.Name, literal.Type, ValKind.Literal);
{
if (literal.Type.IsString)
{
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:
return new Val(bool.Parse(literal.Literal) ? "1" : "0", literal.Type, ValKind.Literal);
default:
throw new ArgumentOutOfRangeException();
{
if (literal.Type.IsBool)
{
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)
@@ -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)
@@ -1140,16 +1202,16 @@ public static class QBEGenerator
{
case NubPrimitiveType { Kind: PrimitiveTypeKind.I64 }:
_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 }:
_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 }:
_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 }:
_builder.AppendLine($" {outputName} =s neg {operand}");
return new Val(outputName, unaryExpression.Type);
return new Val(outputName, unaryExpression.Type, ValKind.Immediate);
}
break;
@@ -1160,7 +1222,7 @@ public static class QBEGenerator
{
case NubPrimitiveType { Kind: PrimitiveTypeKind.Bool }:
_builder.AppendLine($" {outputName} =w xor {operand}, 1");
return new Val(outputName, unaryExpression.Type);
return new Val(outputName, unaryExpression.Type, ValKind.Immediate);
}
break;
@@ -1174,43 +1236,50 @@ public static class QBEGenerator
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 output = VarName();
switch (memberAccess.Expression.Type)
{
case NubArrayType:
{
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:
{
var structDefinition = _definitionTable.LookupStruct(structType.Namespace, structType.Name).GetValue();
var offset = OffsetOf(structDefinition, memberAccess.Member);
var offsetName = VarName();
_builder.AppendLine($" {offsetName} =l add {item}, {offset}");
return offsetName;
_builder.AppendLine($" {output} {QBEAssign(memberAccess.Type)} {QBELoad(memberAccess.Type)} {item}");
break;
}
default:
{
throw new ArgumentOutOfRangeException(nameof(memberAccess.Expression.Type));
throw new ArgumentOutOfRangeException();
}
}
}
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);
return new Val(output, memberAccess.Type, ValKind.Immediate);
}
private static Val EmitFixedArrayInitializer(BoundFixedArrayInitializerNode fixedArrayInitializer)
@@ -1227,7 +1296,7 @@ public static class QBEGenerator
var dataSize = totalSize - 8;
_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)
@@ -1264,6 +1333,7 @@ public static class QBEGenerator
NubFixedArrayType => "l",
NubFuncType => "l",
NubCStringType => "l",
NubStringType => "l",
_ => throw new NotSupportedException($"'{parameter.Type}' type cannot be used in function calls")
};
parameterStrings.Add($"{qbeType} {result}");
@@ -1275,12 +1345,12 @@ public static class QBEGenerator
{
var outputName = VarName();
_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
{
_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)
{
case ValKind.Func:
case ValKind.Literal:
case ValKind.Immediate:
return val.Name;
case ValKind.Variable:
case ValKind.Pointer:
if (IsPointerType(val.Type))
{
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)
{
public string Value { get; } = value;
@@ -1337,7 +1413,7 @@ internal class Variable(string name, Val 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 NubType Type { get; } = type;
@@ -1352,6 +1428,6 @@ internal class Val(string name, NubType type, ValKind kind = ValKind.Variable)
internal enum ValKind
{
Func,
Variable,
Literal
Pointer,
Immediate
}

View File

@@ -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 FixedArrayInitializerNode(IEnumerable<Token> Tokens, NubType ElementType, int Capacity) : 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 DereferenceNode(IEnumerable<Token> Tokens, ExpressionNode Expression) : LValueNode(Tokens);

View File

@@ -668,7 +668,7 @@ public static class Parser
if (name.Value == "string")
{
return new NubArrayType(NubPrimitiveType.U8);
return new NubStringType();
}
if (name.Value == "cstring")

View File

@@ -347,7 +347,7 @@ public static class Binder
{
LiteralKind.Integer => NubPrimitiveType.I64,
LiteralKind.Float => NubPrimitiveType.F64,
LiteralKind.String => new NubCStringType(),
LiteralKind.String => new NubStringType(),
LiteralKind.Bool => NubPrimitiveType.Bool,
_ => throw new ArgumentOutOfRangeException()
};
@@ -364,10 +364,12 @@ public static class Binder
switch (boundExpression.Type)
{
case NubArrayType:
case NubStringType:
case NubCStringType:
{
if (expression.Member == "count")
{
type = NubPrimitiveType.I64;
type = NubPrimitiveType.U64;
}
break;

View File

@@ -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 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 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 BoundDereferenceNode(IEnumerable<Token> Tokens, NubType Type, BoundExpressionNode Expression) : BoundLValueNode(Tokens, Type);

View File

@@ -4,21 +4,6 @@ namespace Syntax.Typing;
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
{
Kind: PrimitiveTypeKind.I8
@@ -45,6 +30,15 @@ public abstract class NubType
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 int GetHashCode();
public abstract override string ToString();
@@ -54,7 +48,7 @@ public class NubCStringType : NubType
{
public override bool Equals(object? obj)
{
return obj is NubCStringType other;
return obj is NubCStringType;
}
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 NubType ReturnType { get; } = returnType;