...
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
namespace c
|
||||
|
||||
// extern func printf(fmt: ^u8, ...args: any): void
|
||||
extern func puts(fmt: []u8)
|
||||
extern func puts(fmt: cstring)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
namespace main
|
||||
|
||||
export func main(args: [][]u8): i64 {
|
||||
let x: []u8
|
||||
export func main(args: []cstring): i64 {
|
||||
let x: cstring
|
||||
|
||||
x = args[0]
|
||||
|
||||
|
||||
@@ -89,6 +89,10 @@ foreach (var compilationUnit in compilationUnits)
|
||||
File.WriteAllText(ssaPath, ssa);
|
||||
|
||||
var asm = await QBE.Invoke(ssa);
|
||||
if (asm == null)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
var asmPath = Path.ChangeExtension(outputPath, "s");
|
||||
await File.WriteAllTextAsync(asmPath, asm);
|
||||
|
||||
@@ -4,7 +4,7 @@ namespace CLI;
|
||||
|
||||
public static class QBE
|
||||
{
|
||||
public static async Task<string> Invoke(string ssa)
|
||||
public static async Task<string?> Invoke(string ssa)
|
||||
{
|
||||
using var qbeProcess = new Process();
|
||||
qbeProcess.StartInfo = new ProcessStartInfo
|
||||
@@ -22,16 +22,16 @@ public static class QBE
|
||||
await qbeProcess.StandardInput.WriteAsync(ssa);
|
||||
qbeProcess.StandardInput.Close();
|
||||
|
||||
var assemblyCode = await qbeProcess.StandardOutput.ReadToEndAsync();
|
||||
var qbeErrors = await qbeProcess.StandardError.ReadToEndAsync();
|
||||
|
||||
await qbeProcess.WaitForExitAsync();
|
||||
|
||||
if (qbeProcess.ExitCode != 0)
|
||||
var qbeErrors = await qbeProcess.StandardError.ReadToEndAsync();
|
||||
if (!string.IsNullOrWhiteSpace(qbeErrors))
|
||||
{
|
||||
throw new Exception($"QBE error:\n{qbeErrors}");
|
||||
await Console.Error.WriteLineAsync("qbe error:\n" + qbeErrors);
|
||||
}
|
||||
|
||||
return assemblyCode;
|
||||
var asm = await qbeProcess.StandardOutput.ReadToEndAsync();
|
||||
|
||||
return qbeProcess.ExitCode == 0 ? asm : null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
.intel_syntax noprefix
|
||||
|
||||
.equ SYS_MMAP, 9
|
||||
.equ SYS_MUNMAP, 11
|
||||
|
||||
.text
|
||||
.globl nub_strlen
|
||||
@@ -79,22 +78,3 @@ function_exit:
|
||||
pop r12
|
||||
pop rbx
|
||||
ret
|
||||
|
||||
.text
|
||||
.globl nub_string_free
|
||||
# func nub_string_free(string: []u8): void
|
||||
nub_string_free:
|
||||
test rdi, rdi
|
||||
jz free_exit
|
||||
|
||||
mov rsi, [rdi]
|
||||
add rsi, 8
|
||||
|
||||
# Round up to page size
|
||||
add rsi, 4095
|
||||
and rsi, -4096
|
||||
|
||||
mov rax, SYS_MUNMAP
|
||||
syscall
|
||||
free_exit:
|
||||
ret
|
||||
|
||||
@@ -122,6 +122,7 @@ public static class QBEGenerator
|
||||
NubStructType => "storel",
|
||||
NubFixedArrayType => "storel",
|
||||
NubFuncType => "storel",
|
||||
NubCStringType => "storel",
|
||||
_ => throw new NotSupportedException($"'{type}' type cannot be used in store instructions")
|
||||
};
|
||||
}
|
||||
@@ -150,6 +151,7 @@ public static class QBEGenerator
|
||||
NubStructType => "loadl",
|
||||
NubFixedArrayType => "loadl",
|
||||
NubFuncType => "loadl",
|
||||
NubCStringType => "loadl",
|
||||
_ => throw new NotSupportedException($"'{type}' type cannot be used in load instructions")
|
||||
};
|
||||
}
|
||||
@@ -178,6 +180,7 @@ public static class QBEGenerator
|
||||
NubStructType => "=l",
|
||||
NubFixedArrayType => "=l",
|
||||
NubFuncType => "=l",
|
||||
NubCStringType => "=l",
|
||||
_ => throw new NotSupportedException($"'{type}' type cannot be used in variables")
|
||||
};
|
||||
}
|
||||
@@ -204,6 +207,7 @@ public static class QBEGenerator
|
||||
}
|
||||
case NubPointerType:
|
||||
case NubArrayType:
|
||||
case NubCStringType:
|
||||
case NubFuncType:
|
||||
{
|
||||
return 8;
|
||||
@@ -263,6 +267,7 @@ public static class QBEGenerator
|
||||
}
|
||||
case NubPointerType:
|
||||
case NubArrayType:
|
||||
case NubCStringType:
|
||||
case NubFuncType:
|
||||
{
|
||||
return 8;
|
||||
@@ -300,16 +305,7 @@ public static class QBEGenerator
|
||||
|
||||
private static bool IsPointerType(NubType type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
NubPointerType => false,
|
||||
NubPrimitiveType => false,
|
||||
NubStructType => true,
|
||||
NubArrayType => true,
|
||||
NubFixedArrayType => true,
|
||||
NubFuncType => false,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(type))
|
||||
};
|
||||
return type is NubStructType or NubArrayType or NubFixedArrayType;
|
||||
}
|
||||
|
||||
private static void GenerateFuncDefinition(string name, List<FuncParameter> parameters, NubType returnType, BlockNode body, bool exported)
|
||||
@@ -347,6 +343,7 @@ public static class QBEGenerator
|
||||
NubStructType structType => StructName(_definitionTable.LookupStruct(structType.Namespace, structType.Name).GetValue()),
|
||||
NubFixedArrayType => "l",
|
||||
NubFuncType => "l",
|
||||
NubCStringType => "l",
|
||||
_ => throw new NotSupportedException($"'{returnType}' type cannot be used as a function return type")
|
||||
});
|
||||
_builder.Append(' ');
|
||||
@@ -378,6 +375,7 @@ public static class QBEGenerator
|
||||
NubStructType structType => StructName(_definitionTable.LookupStruct(structType.Namespace, structType.Name).GetValue()),
|
||||
NubFixedArrayType => "l",
|
||||
NubFuncType => "l",
|
||||
NubCStringType => "l",
|
||||
_ => throw new NotSupportedException($"'{parameter.Type}' type cannot be used as a function parameter type")
|
||||
};
|
||||
|
||||
@@ -459,6 +457,7 @@ public static class QBEGenerator
|
||||
NubStructType structType => StructName(_definitionTable.LookupStruct(structType.Namespace, structType.Name).GetValue()),
|
||||
NubFixedArrayType fixedArrayType => $"b {SizeOf(fixedArrayType)}",
|
||||
NubFuncType => "l",
|
||||
NubCStringType => "l",
|
||||
_ => throw new NotSupportedException($"'{structDefinitionField.Type}' type cannot be used in structs")
|
||||
};
|
||||
_builder.Append(qbeType + ", ");
|
||||
@@ -1200,12 +1199,19 @@ public static class QBEGenerator
|
||||
var item = GenerateExpression(memberAccess.Expression);
|
||||
switch (memberAccess.Expression.Type)
|
||||
{
|
||||
case NubArrayType:
|
||||
case NubArrayType arrayType:
|
||||
{
|
||||
if (memberAccess.Member == "count")
|
||||
{
|
||||
return item;
|
||||
}
|
||||
|
||||
if (arrayType.ElementType is NubPrimitiveType { Kind: PrimitiveTypeKind.U8 } && memberAccess.Member == "cstring")
|
||||
{
|
||||
var result = VarName();
|
||||
_builder.AppendLine($" {result} =l call $nub_string_to_cstring(l {item})");
|
||||
return result;
|
||||
}
|
||||
|
||||
throw new UnreachableException(nameof(memberAccess.Member));
|
||||
}
|
||||
@@ -1291,6 +1297,7 @@ public static class QBEGenerator
|
||||
NubStructType structType => StructName(_definitionTable.LookupStruct(structType.Namespace, structType.Name).GetValue()),
|
||||
NubFixedArrayType => "l",
|
||||
NubFuncType => "l",
|
||||
NubCStringType => "l",
|
||||
_ => throw new NotSupportedException($"'{parameter.Type}' type cannot be used in function calls")
|
||||
};
|
||||
parameterStrings.Add($"{qbeType} {result}");
|
||||
|
||||
@@ -670,6 +670,11 @@ public static class Parser
|
||||
return new NubArrayType(NubPrimitiveType.U8);
|
||||
}
|
||||
|
||||
if (name.Value == "cstring")
|
||||
{
|
||||
return new NubCStringType();
|
||||
}
|
||||
|
||||
if (NubPrimitiveType.TryParse(name.Value, out var primitiveTypeKind))
|
||||
{
|
||||
return new NubPrimitiveType(primitiveTypeKind.Value);
|
||||
|
||||
@@ -48,6 +48,24 @@ public abstract class NubType
|
||||
public abstract override string ToString();
|
||||
}
|
||||
|
||||
public class NubCStringType : NubType
|
||||
{
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is NubCStringType other;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return "cstring".GetHashCode();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "cstring";
|
||||
}
|
||||
}
|
||||
|
||||
public class NubFuncType(NubType returnType, List<NubType> parameters) : NubType
|
||||
{
|
||||
public NubType ReturnType { get; } = returnType;
|
||||
@@ -163,7 +181,7 @@ public class NubAnyType : NubType
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return GetType().GetHashCode();
|
||||
return "any".GetHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -422,12 +422,6 @@ public static class TypeChecker
|
||||
var exprType = CheckExpression(addressOf.Expression);
|
||||
if (exprType == null) return null;
|
||||
|
||||
if (addressOf.Expression is not (IdentifierNode or MemberAccessNode))
|
||||
{
|
||||
ReportError($"Cannot take the address of {exprType}", addressOf.Expression);
|
||||
return null;
|
||||
}
|
||||
|
||||
return new NubPointerType(exprType);
|
||||
}
|
||||
|
||||
@@ -569,13 +563,18 @@ public static class TypeChecker
|
||||
|
||||
switch (expressionType)
|
||||
{
|
||||
case NubArrayType:
|
||||
case NubArrayType arrayType:
|
||||
{
|
||||
if (memberAccess.Member == "count")
|
||||
{
|
||||
return NubPrimitiveType.I64;
|
||||
}
|
||||
|
||||
if (arrayType.ElementType is NubPrimitiveType { Kind: PrimitiveTypeKind.U8 } && memberAccess.Member == "cstring")
|
||||
{
|
||||
return new NubCStringType();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case NubStructType structType:
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
},
|
||||
{
|
||||
"name": "storage.type.primitive.nub",
|
||||
"match": "\\b(i8|i16|i32|i64|u8|u16|u32|u64|f32|f64|bool|string|void|any)\\b"
|
||||
"match": "\\b(i8|i16|i32|i64|u8|u16|u32|u64|f32|f64|bool|string|cstring|void|any)\\b"
|
||||
},
|
||||
{
|
||||
"name": "storage.type.array.nub",
|
||||
|
||||
Reference in New Issue
Block a user