...
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: ^u8, ...args: any): void
|
||||||
extern func puts(fmt: []u8)
|
extern func puts(fmt: cstring)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
namespace main
|
namespace main
|
||||||
|
|
||||||
export func main(args: [][]u8): i64 {
|
export func main(args: []cstring): i64 {
|
||||||
let x: []u8
|
let x: cstring
|
||||||
|
|
||||||
x = args[0]
|
x = args[0]
|
||||||
|
|
||||||
|
|||||||
@@ -89,6 +89,10 @@ foreach (var compilationUnit in compilationUnits)
|
|||||||
File.WriteAllText(ssaPath, ssa);
|
File.WriteAllText(ssaPath, ssa);
|
||||||
|
|
||||||
var asm = await QBE.Invoke(ssa);
|
var asm = await QBE.Invoke(ssa);
|
||||||
|
if (asm == null)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
var asmPath = Path.ChangeExtension(outputPath, "s");
|
var asmPath = Path.ChangeExtension(outputPath, "s");
|
||||||
await File.WriteAllTextAsync(asmPath, asm);
|
await File.WriteAllTextAsync(asmPath, asm);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ namespace CLI;
|
|||||||
|
|
||||||
public static class QBE
|
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();
|
using var qbeProcess = new Process();
|
||||||
qbeProcess.StartInfo = new ProcessStartInfo
|
qbeProcess.StartInfo = new ProcessStartInfo
|
||||||
@@ -22,16 +22,16 @@ public static class QBE
|
|||||||
await qbeProcess.StandardInput.WriteAsync(ssa);
|
await qbeProcess.StandardInput.WriteAsync(ssa);
|
||||||
qbeProcess.StandardInput.Close();
|
qbeProcess.StandardInput.Close();
|
||||||
|
|
||||||
var assemblyCode = await qbeProcess.StandardOutput.ReadToEndAsync();
|
|
||||||
var qbeErrors = await qbeProcess.StandardError.ReadToEndAsync();
|
|
||||||
|
|
||||||
await qbeProcess.WaitForExitAsync();
|
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
|
.intel_syntax noprefix
|
||||||
|
|
||||||
.equ SYS_MMAP, 9
|
.equ SYS_MMAP, 9
|
||||||
.equ SYS_MUNMAP, 11
|
|
||||||
|
|
||||||
.text
|
.text
|
||||||
.globl nub_strlen
|
.globl nub_strlen
|
||||||
@@ -79,22 +78,3 @@ function_exit:
|
|||||||
pop r12
|
pop r12
|
||||||
pop rbx
|
pop rbx
|
||||||
ret
|
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",
|
NubStructType => "storel",
|
||||||
NubFixedArrayType => "storel",
|
NubFixedArrayType => "storel",
|
||||||
NubFuncType => "storel",
|
NubFuncType => "storel",
|
||||||
|
NubCStringType => "storel",
|
||||||
_ => throw new NotSupportedException($"'{type}' type cannot be used in store instructions")
|
_ => throw new NotSupportedException($"'{type}' type cannot be used in store instructions")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -150,6 +151,7 @@ public static class QBEGenerator
|
|||||||
NubStructType => "loadl",
|
NubStructType => "loadl",
|
||||||
NubFixedArrayType => "loadl",
|
NubFixedArrayType => "loadl",
|
||||||
NubFuncType => "loadl",
|
NubFuncType => "loadl",
|
||||||
|
NubCStringType => "loadl",
|
||||||
_ => throw new NotSupportedException($"'{type}' type cannot be used in load instructions")
|
_ => throw new NotSupportedException($"'{type}' type cannot be used in load instructions")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -178,6 +180,7 @@ public static class QBEGenerator
|
|||||||
NubStructType => "=l",
|
NubStructType => "=l",
|
||||||
NubFixedArrayType => "=l",
|
NubFixedArrayType => "=l",
|
||||||
NubFuncType => "=l",
|
NubFuncType => "=l",
|
||||||
|
NubCStringType => "=l",
|
||||||
_ => throw new NotSupportedException($"'{type}' type cannot be used in variables")
|
_ => throw new NotSupportedException($"'{type}' type cannot be used in variables")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -204,6 +207,7 @@ public static class QBEGenerator
|
|||||||
}
|
}
|
||||||
case NubPointerType:
|
case NubPointerType:
|
||||||
case NubArrayType:
|
case NubArrayType:
|
||||||
|
case NubCStringType:
|
||||||
case NubFuncType:
|
case NubFuncType:
|
||||||
{
|
{
|
||||||
return 8;
|
return 8;
|
||||||
@@ -263,6 +267,7 @@ public static class QBEGenerator
|
|||||||
}
|
}
|
||||||
case NubPointerType:
|
case NubPointerType:
|
||||||
case NubArrayType:
|
case NubArrayType:
|
||||||
|
case NubCStringType:
|
||||||
case NubFuncType:
|
case NubFuncType:
|
||||||
{
|
{
|
||||||
return 8;
|
return 8;
|
||||||
@@ -300,16 +305,7 @@ public static class QBEGenerator
|
|||||||
|
|
||||||
private static bool IsPointerType(NubType type)
|
private static bool IsPointerType(NubType type)
|
||||||
{
|
{
|
||||||
return type switch
|
return type is NubStructType or NubArrayType or NubFixedArrayType;
|
||||||
{
|
|
||||||
NubPointerType => false,
|
|
||||||
NubPrimitiveType => false,
|
|
||||||
NubStructType => true,
|
|
||||||
NubArrayType => true,
|
|
||||||
NubFixedArrayType => true,
|
|
||||||
NubFuncType => false,
|
|
||||||
_ => throw new ArgumentOutOfRangeException(nameof(type))
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void GenerateFuncDefinition(string name, List<FuncParameter> parameters, NubType returnType, BlockNode body, bool exported)
|
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()),
|
NubStructType structType => StructName(_definitionTable.LookupStruct(structType.Namespace, structType.Name).GetValue()),
|
||||||
NubFixedArrayType => "l",
|
NubFixedArrayType => "l",
|
||||||
NubFuncType => "l",
|
NubFuncType => "l",
|
||||||
|
NubCStringType => "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(' ');
|
||||||
@@ -378,6 +375,7 @@ public static class QBEGenerator
|
|||||||
NubStructType structType => StructName(_definitionTable.LookupStruct(structType.Namespace, structType.Name).GetValue()),
|
NubStructType structType => StructName(_definitionTable.LookupStruct(structType.Namespace, structType.Name).GetValue()),
|
||||||
NubFixedArrayType => "l",
|
NubFixedArrayType => "l",
|
||||||
NubFuncType => "l",
|
NubFuncType => "l",
|
||||||
|
NubCStringType => "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")
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -459,6 +457,7 @@ public static class QBEGenerator
|
|||||||
NubStructType structType => StructName(_definitionTable.LookupStruct(structType.Namespace, structType.Name).GetValue()),
|
NubStructType structType => StructName(_definitionTable.LookupStruct(structType.Namespace, structType.Name).GetValue()),
|
||||||
NubFixedArrayType fixedArrayType => $"b {SizeOf(fixedArrayType)}",
|
NubFixedArrayType fixedArrayType => $"b {SizeOf(fixedArrayType)}",
|
||||||
NubFuncType => "l",
|
NubFuncType => "l",
|
||||||
|
NubCStringType => "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 + ", ");
|
||||||
@@ -1200,13 +1199,20 @@ public static class QBEGenerator
|
|||||||
var item = GenerateExpression(memberAccess.Expression);
|
var item = GenerateExpression(memberAccess.Expression);
|
||||||
switch (memberAccess.Expression.Type)
|
switch (memberAccess.Expression.Type)
|
||||||
{
|
{
|
||||||
case NubArrayType:
|
case NubArrayType arrayType:
|
||||||
{
|
{
|
||||||
if (memberAccess.Member == "count")
|
if (memberAccess.Member == "count")
|
||||||
{
|
{
|
||||||
return item;
|
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));
|
throw new UnreachableException(nameof(memberAccess.Member));
|
||||||
}
|
}
|
||||||
case NubStructType structType:
|
case NubStructType structType:
|
||||||
@@ -1291,6 +1297,7 @@ public static class QBEGenerator
|
|||||||
NubStructType structType => StructName(_definitionTable.LookupStruct(structType.Namespace, structType.Name).GetValue()),
|
NubStructType structType => StructName(_definitionTable.LookupStruct(structType.Namespace, structType.Name).GetValue()),
|
||||||
NubFixedArrayType => "l",
|
NubFixedArrayType => "l",
|
||||||
NubFuncType => "l",
|
NubFuncType => "l",
|
||||||
|
NubCStringType => "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}");
|
||||||
|
|||||||
@@ -670,6 +670,11 @@ public static class Parser
|
|||||||
return new NubArrayType(NubPrimitiveType.U8);
|
return new NubArrayType(NubPrimitiveType.U8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (name.Value == "cstring")
|
||||||
|
{
|
||||||
|
return new NubCStringType();
|
||||||
|
}
|
||||||
|
|
||||||
if (NubPrimitiveType.TryParse(name.Value, out var primitiveTypeKind))
|
if (NubPrimitiveType.TryParse(name.Value, out var primitiveTypeKind))
|
||||||
{
|
{
|
||||||
return new NubPrimitiveType(primitiveTypeKind.Value);
|
return new NubPrimitiveType(primitiveTypeKind.Value);
|
||||||
|
|||||||
@@ -48,6 +48,24 @@ public abstract class NubType
|
|||||||
public abstract override string ToString();
|
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 class NubFuncType(NubType returnType, List<NubType> parameters) : NubType
|
||||||
{
|
{
|
||||||
public NubType ReturnType { get; } = returnType;
|
public NubType ReturnType { get; } = returnType;
|
||||||
@@ -163,7 +181,7 @@ public class NubAnyType : NubType
|
|||||||
|
|
||||||
public override int GetHashCode()
|
public override int GetHashCode()
|
||||||
{
|
{
|
||||||
return GetType().GetHashCode();
|
return "any".GetHashCode();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -422,12 +422,6 @@ public static class TypeChecker
|
|||||||
var exprType = CheckExpression(addressOf.Expression);
|
var exprType = CheckExpression(addressOf.Expression);
|
||||||
if (exprType == null) return null;
|
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);
|
return new NubPointerType(exprType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -569,13 +563,18 @@ public static class TypeChecker
|
|||||||
|
|
||||||
switch (expressionType)
|
switch (expressionType)
|
||||||
{
|
{
|
||||||
case NubArrayType:
|
case NubArrayType arrayType:
|
||||||
{
|
{
|
||||||
if (memberAccess.Member == "count")
|
if (memberAccess.Member == "count")
|
||||||
{
|
{
|
||||||
return NubPrimitiveType.I64;
|
return NubPrimitiveType.I64;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (arrayType.ElementType is NubPrimitiveType { Kind: PrimitiveTypeKind.U8 } && memberAccess.Member == "cstring")
|
||||||
|
{
|
||||||
|
return new NubCStringType();
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case NubStructType structType:
|
case NubStructType structType:
|
||||||
|
|||||||
@@ -79,7 +79,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "storage.type.primitive.nub",
|
"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",
|
"name": "storage.type.array.nub",
|
||||||
|
|||||||
Reference in New Issue
Block a user