diff --git a/example/c.nub b/example/c.nub
index c24b1d3..8347d6a 100644
--- a/example/c.nub
+++ b/example/c.nub
@@ -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)
diff --git a/example/main.nub b/example/main.nub
index c1ded04..6b487b5 100644
--- a/example/main.nub
+++ b/example/main.nub
@@ -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
}
diff --git a/src/CLI/CLI.csproj b/src/CLI/CLI.csproj
index b1f4bc4..c8dff8b 100644
--- a/src/CLI/CLI.csproj
+++ b/src/CLI/CLI.csproj
@@ -14,13 +14,11 @@
-
-
-
+
diff --git a/src/CLI/Runtime/nub_cstring.s b/src/CLI/Runtime/nub_cstring.s
new file mode 100644
index 0000000..8acef4f
--- /dev/null
+++ b/src/CLI/Runtime/nub_cstring.s
@@ -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
diff --git a/src/CLI/Runtime/nub_mem.s b/src/CLI/Runtime/nub_mem.s
index d2b5f72..27cf71c 100644
--- a/src/CLI/Runtime/nub_mem.s
+++ b/src/CLI/Runtime/nub_mem.s
@@ -6,6 +6,7 @@
nub_memcpy:
mov rcx, rdx
rep movsb
+ ret
.text
.globl nub_memset
diff --git a/src/CLI/Runtime/nub_string.s b/src/CLI/Runtime/nub_string.s
index 879e4f8..dccbd5d 100644
--- a/src/CLI/Runtime/nub_string.s
+++ b/src/CLI/Runtime/nub_string.s
@@ -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
diff --git a/src/Generation/QBE/QBEGenerator.cs b/src/Generation/QBE/QBEGenerator.cs
index 52cf3be..d8850c6 100644
--- a/src/Generation/QBE/QBEGenerator.cs
+++ b/src/Generation/QBE/QBEGenerator.cs
@@ -16,6 +16,7 @@ public static class QBEGenerator
private static StringBuilder _builder = new();
private static List _cStringLiterals = [];
+ private static List _stringLiterals = [];
private static Stack _breakLabels = [];
private static Stack _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
}
\ No newline at end of file
diff --git a/src/Syntax/Parsing/Node/Expression.cs b/src/Syntax/Parsing/Node/Expression.cs
index d77e12a..a71316b 100644
--- a/src/Syntax/Parsing/Node/Expression.cs
+++ b/src/Syntax/Parsing/Node/Expression.cs
@@ -39,6 +39,6 @@ public record AnonymousFuncNode(IEnumerable Tokens, List P
public record AddressOfNode(IEnumerable Tokens, LValueNode Expression) : ExpressionNode(Tokens);
public record FixedArrayInitializerNode(IEnumerable Tokens, NubType ElementType, int Capacity) : ExpressionNode(Tokens);
public record LiteralNode(IEnumerable Tokens, string Literal, LiteralKind Kind) : ExpressionNode(Tokens);
-public record MemberAccessNode(IEnumerable Tokens, ExpressionNode Expression, string Member) : LValueNode(Tokens);
+public record MemberAccessNode(IEnumerable Tokens, ExpressionNode Expression, string Member) : ExpressionNode(Tokens);
public record StructInitializerNode(IEnumerable Tokens, NubStructType StructType, Dictionary Initializers) : ExpressionNode(Tokens);
public record DereferenceNode(IEnumerable Tokens, ExpressionNode Expression) : LValueNode(Tokens);
diff --git a/src/Syntax/Parsing/Parser.cs b/src/Syntax/Parsing/Parser.cs
index 75cf666..546310f 100644
--- a/src/Syntax/Parsing/Parser.cs
+++ b/src/Syntax/Parsing/Parser.cs
@@ -668,7 +668,7 @@ public static class Parser
if (name.Value == "string")
{
- return new NubArrayType(NubPrimitiveType.U8);
+ return new NubStringType();
}
if (name.Value == "cstring")
diff --git a/src/Syntax/Typing/Binder.cs b/src/Syntax/Typing/Binder.cs
index a82667b..306d40f 100644
--- a/src/Syntax/Typing/Binder.cs
+++ b/src/Syntax/Typing/Binder.cs
@@ -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;
diff --git a/src/Syntax/Typing/BoundNode/Expression.cs b/src/Syntax/Typing/BoundNode/Expression.cs
index 5a23807..f6f204f 100644
--- a/src/Syntax/Typing/BoundNode/Expression.cs
+++ b/src/Syntax/Typing/BoundNode/Expression.cs
@@ -16,6 +16,6 @@ public record BoundAnonymousFuncNode(IEnumerable Tokens, NubType Type, Li
public record BoundAddressOfNode(IEnumerable Tokens, NubType Type, BoundLValueNode Expression) : BoundExpressionNode(Tokens, Type);
public record BoundFixedArrayInitializerNode(IEnumerable Tokens, NubType Type, NubType ElementType, int Capacity) : BoundExpressionNode(Tokens, Type);
public record BoundLiteralNode(IEnumerable Tokens, NubType Type, string Literal, LiteralKind Kind) : BoundExpressionNode(Tokens, Type);
-public record BoundMemberAccessNode(IEnumerable Tokens, NubType Type, BoundExpressionNode Expression, string Member) : BoundLValueNode(Tokens, Type);
+public record BoundMemberAccessNode(IEnumerable Tokens, NubType Type, BoundExpressionNode Expression, string Member) : BoundExpressionNode(Tokens, Type);
public record BoundStructInitializerNode(IEnumerable Tokens, NubType Type, NubStructType StructType, Dictionary Initializers) : BoundExpressionNode(Tokens, Type);
public record BoundDereferenceNode(IEnumerable Tokens, NubType Type, BoundExpressionNode Expression) : BoundLValueNode(Tokens, Type);
diff --git a/src/Syntax/Typing/NubType.cs b/src/Syntax/Typing/NubType.cs
index fd1ea4c..1c89f69 100644
--- a/src/Syntax/Typing/NubType.cs
+++ b/src/Syntax/Typing/NubType.cs
@@ -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 parameters) : NubType
{
public NubType ReturnType { get; } = returnType;