...
This commit is contained in:
3
build.sh
3
build.sh
@@ -7,9 +7,8 @@ gcc -c -g -fno-stack-protector -fno-builtin std/baseline/gc.c -o out/gc.o
|
|||||||
nasm -g -felf64 std/baseline/str_cmp.asm -o out/str_cmp.o
|
nasm -g -felf64 std/baseline/str_cmp.asm -o out/str_cmp.o
|
||||||
|
|
||||||
nasm -g -felf64 std/core/str_len.asm -o out/str_len.o
|
nasm -g -felf64 std/core/str_len.asm -o out/str_len.o
|
||||||
nasm -g -felf64 std/core/arr_size.asm -o out/arr_size.o
|
|
||||||
nasm -g -felf64 std/core/itoa.asm -o out/itoa.o
|
nasm -g -felf64 std/core/itoa.asm -o out/itoa.o
|
||||||
|
|
||||||
nasm -g -felf64 out/out.asm -o out/out.o
|
nasm -g -felf64 out/out.asm -o out/out.o
|
||||||
|
|
||||||
gcc -no-pie -nostartfiles -o out/program out/gc.o out/str_cmp.o out/str_len.o out/arr_size.o out/itoa.o out/out.o
|
gcc -no-pie -nostartfiles -o out/program out/gc.o out/str_cmp.o out/str_len.o out/itoa.o out/out.o
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
extern func arr_size(array: Array<Any>): int64;
|
|
||||||
@@ -2,16 +2,16 @@ let SYS_WRITE = 1;
|
|||||||
let STD_OUT = 1;
|
let STD_OUT = 1;
|
||||||
let STD_ERR = 2;
|
let STD_ERR = 2;
|
||||||
|
|
||||||
func print(msg: String) {
|
func print(msg: string) {
|
||||||
syscall(SYS_WRITE, STD_OUT, msg, str_len(msg));
|
syscall(SYS_WRITE, STD_OUT, msg, str_len(msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
func print(value1: int64) {
|
func print(value: int64) {
|
||||||
print(itoa(value1));
|
print(itoa(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
func print(value2: bool) {
|
func print(value: bool) {
|
||||||
if value2 {
|
if value {
|
||||||
print("true");
|
print("true");
|
||||||
} else {
|
} else {
|
||||||
print("false");
|
print("false");
|
||||||
@@ -22,17 +22,17 @@ func println() {
|
|||||||
print("\n");
|
print("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
func println(msg: String) {
|
func println(msg: string) {
|
||||||
print(msg);
|
print(msg);
|
||||||
println();
|
println();
|
||||||
}
|
}
|
||||||
|
|
||||||
func println(value3: bool) {
|
func println(value: bool) {
|
||||||
print(value3);
|
print(value);
|
||||||
println();
|
println();
|
||||||
}
|
}
|
||||||
|
|
||||||
func println(value4: int64) {
|
func println(value: int64) {
|
||||||
print(value4);
|
print(value);
|
||||||
println();
|
println();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
extern func str_len(msg: String): int64;
|
extern func str_len(msg: string): int64;
|
||||||
extern func itoa(value: int64): String;
|
extern func itoa(value: int64): string;
|
||||||
|
|||||||
@@ -1,16 +1,5 @@
|
|||||||
import "core";
|
import "core";
|
||||||
|
|
||||||
struct Human {
|
|
||||||
let name: String;
|
|
||||||
let age: int64;
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
while true {
|
println("test");
|
||||||
let x = new Human
|
}
|
||||||
{
|
|
||||||
name = "test",
|
|
||||||
age = 34958743
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
1
lang/.idea/.idea.Nub.Lang/.idea/indexLayout.xml
generated
1
lang/.idea/.idea.Nub.Lang/.idea/indexLayout.xml
generated
@@ -2,6 +2,7 @@
|
|||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="UserContentModel">
|
<component name="UserContentModel">
|
||||||
<attachedFolders>
|
<attachedFolders>
|
||||||
|
<Path>../example</Path>
|
||||||
<Path>../std</Path>
|
<Path>../std</Path>
|
||||||
</attachedFolders>
|
</attachedFolders>
|
||||||
<explicitIncludes />
|
<explicitIncludes />
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ namespace Nub.Lang.Backend.Custom;
|
|||||||
public class Generator
|
public class Generator
|
||||||
{
|
{
|
||||||
private const string Entrypoint = "main";
|
private const string Entrypoint = "main";
|
||||||
private const bool ZeroBasedIndexing = false;
|
|
||||||
|
|
||||||
private readonly List<DefinitionNode> _definitions;
|
private readonly List<DefinitionNode> _definitions;
|
||||||
private readonly SymbolTable _symbolTable;
|
private readonly SymbolTable _symbolTable;
|
||||||
@@ -129,17 +128,20 @@ public class Generator
|
|||||||
}
|
}
|
||||||
case LiteralNode literal:
|
case LiteralNode literal:
|
||||||
{
|
{
|
||||||
if (literal.Type is not PrimitiveType primitiveType)
|
if (literal.LiteralType.Equals(NubType.Int64)
|
||||||
|
|| literal.LiteralType.Equals(NubType.Int32)
|
||||||
|
|| literal.LiteralType.Equals(NubType.Int16)
|
||||||
|
|| literal.LiteralType.Equals(NubType.Int8))
|
||||||
{
|
{
|
||||||
throw new NotSupportedException("Global variable literals must be of a primitive type");
|
return literal.Literal;
|
||||||
}
|
}
|
||||||
|
|
||||||
return primitiveType.Kind switch
|
if (literal.LiteralType.Equals(NubType.Bool))
|
||||||
{
|
{
|
||||||
PrimitiveTypeKind.Bool => bool.Parse(literal.Literal) ? "1" : "0",
|
return bool.Parse(literal.Literal) ? "1" : "0";
|
||||||
PrimitiveTypeKind.Int64 or PrimitiveTypeKind.Int32 => $"{literal.Literal}",
|
}
|
||||||
_ => throw new ArgumentOutOfRangeException()
|
|
||||||
};
|
throw new InvalidOperationException("BAD");
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
@@ -194,9 +196,6 @@ public class Generator
|
|||||||
{
|
{
|
||||||
switch (statement)
|
switch (statement)
|
||||||
{
|
{
|
||||||
case ArrayIndexAssignmentNode arrayIndexAssignment:
|
|
||||||
GenerateArrayIndexAssignment(arrayIndexAssignment, func);
|
|
||||||
break;
|
|
||||||
case BreakNode:
|
case BreakNode:
|
||||||
GenerateBreak();
|
GenerateBreak();
|
||||||
break;
|
break;
|
||||||
@@ -239,15 +238,6 @@ public class Generator
|
|||||||
_builder.AppendLine($" jmp {_loops.Peek().StartLabel}");
|
_builder.AppendLine($" jmp {_loops.Peek().StartLabel}");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GenerateArrayIndexAssignment(ArrayIndexAssignmentNode arrayIndexAssignment, LocalFunc func)
|
|
||||||
{
|
|
||||||
GenerateExpression(arrayIndexAssignment.Value, func);
|
|
||||||
_builder.AppendLine(" push rax");
|
|
||||||
GenerateArrayIndexPointerAccess(arrayIndexAssignment.Identifier, arrayIndexAssignment.Index, func);
|
|
||||||
_builder.AppendLine(" pop rdx");
|
|
||||||
_builder.AppendLine(" mov [rax], rdx");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void GenerateIf(IfNode ifStatement, LocalFunc func)
|
private void GenerateIf(IfNode ifStatement, LocalFunc func)
|
||||||
{
|
{
|
||||||
var endLabel = _labelFactory.Create();
|
var endLabel = _labelFactory.Create();
|
||||||
@@ -319,12 +309,6 @@ public class Generator
|
|||||||
{
|
{
|
||||||
switch (expression)
|
switch (expression)
|
||||||
{
|
{
|
||||||
case ArrayIndexAccessNode arrayIndexAccess:
|
|
||||||
GenerateArrayIndexAccess(arrayIndexAccess, func);
|
|
||||||
break;
|
|
||||||
case ArrayInitializerNode arrayInitializer:
|
|
||||||
GenerateArrayInitializer(arrayInitializer);
|
|
||||||
break;
|
|
||||||
case BinaryExpressionNode binaryExpression:
|
case BinaryExpressionNode binaryExpression:
|
||||||
GenerateBinaryExpression(binaryExpression, func);
|
GenerateBinaryExpression(binaryExpression, func);
|
||||||
break;
|
break;
|
||||||
@@ -355,31 +339,21 @@ public class Generator
|
|||||||
{
|
{
|
||||||
var variable = func.ResolveLocalVariable(structMemberAccessor.Members[0]);
|
var variable = func.ResolveLocalVariable(structMemberAccessor.Members[0]);
|
||||||
|
|
||||||
if (variable.Type is not StructType structType)
|
|
||||||
{
|
|
||||||
throw new Exception($"Cannot access struct member on {variable} since it is not a struct type");
|
|
||||||
}
|
|
||||||
|
|
||||||
_builder.AppendLine($" mov rax, [rbp - {variable.Offset}]");
|
_builder.AppendLine($" mov rax, [rbp - {variable.Offset}]");
|
||||||
|
|
||||||
Type prevMemberType = structType;
|
var prevMemberType = variable.Type;
|
||||||
for (var i = 1; i < structMemberAccessor.Members.Count; i++)
|
for (var i = 1; i < structMemberAccessor.Members.Count; i++)
|
||||||
{
|
{
|
||||||
if (prevMemberType is not StructType prevMemberStructType)
|
var structDefinition = _definitions.OfType<StructDefinitionNode>().FirstOrDefault(sd => sd.Name == prevMemberType.Name);
|
||||||
{
|
|
||||||
throw new Exception($"Cannot access {structMemberAccessor.Members[i]} on type {prevMemberType} because it is not a struct type");
|
|
||||||
}
|
|
||||||
|
|
||||||
var structDefinition = _definitions.OfType<StructDefinitionNode>().FirstOrDefault(sd => sd.Name == prevMemberStructType.Name);
|
|
||||||
if (structDefinition == null)
|
if (structDefinition == null)
|
||||||
{
|
{
|
||||||
throw new Exception($"Struct {prevMemberStructType} is not defined");
|
throw new Exception($"Struct {prevMemberType} is not defined");
|
||||||
}
|
}
|
||||||
|
|
||||||
var member = structDefinition.Members.FirstOrDefault(m => m.Name == structMemberAccessor.Members[i]);
|
var member = structDefinition.Members.FirstOrDefault(m => m.Name == structMemberAccessor.Members[i]);
|
||||||
if (member == null)
|
if (member == null)
|
||||||
{
|
{
|
||||||
throw new Exception($"Struct {prevMemberStructType} has no member with name {structMemberAccessor.Members[i]}");
|
throw new Exception($"Struct {prevMemberType} has no member with name {structMemberAccessor.Members[i]}");
|
||||||
}
|
}
|
||||||
|
|
||||||
var offset = structDefinition.Members.IndexOf(member);
|
var offset = structDefinition.Members.IndexOf(member);
|
||||||
@@ -389,19 +363,6 @@ public class Generator
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GenerateArrayIndexAccess(ArrayIndexAccessNode arrayIndexAccess, LocalFunc func)
|
|
||||||
{
|
|
||||||
GenerateArrayIndexPointerAccess(arrayIndexAccess.Identifier, arrayIndexAccess.Index, func);
|
|
||||||
_builder.AppendLine(" mov rax, [rax]");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void GenerateArrayInitializer(ArrayInitializerNode arrayInitializer)
|
|
||||||
{
|
|
||||||
_builder.AppendLine($" mov rdi, {8 + arrayInitializer.Length * 8}");
|
|
||||||
_builder.AppendLine(" call gc_alloc");
|
|
||||||
_builder.AppendLine($" mov qword [rax], {arrayInitializer.Length}");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void GenerateBinaryExpression(BinaryExpressionNode binaryExpression, LocalFunc func)
|
private void GenerateBinaryExpression(BinaryExpressionNode binaryExpression, LocalFunc func)
|
||||||
{
|
{
|
||||||
GenerateExpression(binaryExpression.Left, func);
|
GenerateExpression(binaryExpression.Left, func);
|
||||||
@@ -459,108 +420,121 @@ public class Generator
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GenerateComparison(Type type)
|
private void GenerateComparison(NubType type)
|
||||||
{
|
{
|
||||||
switch (type)
|
if (type.Equals(NubType.String))
|
||||||
{
|
{
|
||||||
case AnyType:
|
_builder.AppendLine(" mov rdi, rax");
|
||||||
throw new InvalidOperationException($"Cannot compare type {type}");
|
_builder.AppendLine(" mov rsi, rcx");
|
||||||
case ArrayType:
|
_builder.AppendLine(" call str_cmp");
|
||||||
// compare pointers
|
}
|
||||||
_builder.AppendLine(" cmp rax, rcx");
|
else if (type.Equals(NubType.Bool) || type.Equals(NubType.Int64) || type.Equals(NubType.Int32) || type.Equals(NubType.Int16) || type.Equals(NubType.Int8))
|
||||||
break;
|
{
|
||||||
case PrimitiveType:
|
_builder.AppendLine(" cmp rax, rcx");
|
||||||
_builder.AppendLine(" cmp rax, rcx");
|
}
|
||||||
break;
|
else
|
||||||
case StringType:
|
{
|
||||||
_builder.AppendLine(" mov rdi, rax");
|
throw new ArgumentOutOfRangeException(nameof(type));
|
||||||
_builder.AppendLine(" mov rsi, rcx");
|
|
||||||
_builder.AppendLine(" call str_cmp");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new ArgumentOutOfRangeException(nameof(type));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GenerateBinaryAddition(Type type)
|
private void GenerateBinaryAddition(NubType type)
|
||||||
{
|
{
|
||||||
if (type is not PrimitiveType primitiveType)
|
if (type.Equals(NubType.Int64))
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("Addition can only be done on primitive types");
|
_builder.AppendLine(" add rax, rcx");
|
||||||
}
|
}
|
||||||
|
else if (type.Equals(NubType.Int32))
|
||||||
switch (primitiveType.Kind)
|
|
||||||
{
|
{
|
||||||
case PrimitiveTypeKind.Int64:
|
_builder.AppendLine(" add eax, ecx");
|
||||||
_builder.AppendLine(" add rax, rcx");
|
}
|
||||||
break;
|
else if (type.Equals(NubType.Int16))
|
||||||
case PrimitiveTypeKind.Int32:
|
{
|
||||||
_builder.AppendLine(" add eax, ecx");
|
_builder.AppendLine(" add ax, cx");
|
||||||
break;
|
}
|
||||||
default:
|
else if (type.Equals(NubType.Int8))
|
||||||
throw new InvalidOperationException($"Invalid type {primitiveType.Kind}");
|
{
|
||||||
|
_builder.AppendLine(" add al, cl");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"Invalid type for addition {type}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GenerateBinarySubtraction(Type type)
|
private void GenerateBinarySubtraction(NubType type)
|
||||||
{
|
{
|
||||||
if (type is not PrimitiveType primitiveType)
|
if (type.Equals(NubType.Int64))
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("Subtraction can only be done on primitive types");
|
_builder.AppendLine(" sub rax, rcx");
|
||||||
}
|
}
|
||||||
|
else if (type.Equals(NubType.Int32))
|
||||||
switch (primitiveType.Kind)
|
|
||||||
{
|
{
|
||||||
case PrimitiveTypeKind.Int64:
|
_builder.AppendLine(" sub eax, ecx");
|
||||||
_builder.AppendLine(" sub rax, rcx");
|
}
|
||||||
break;
|
else if (type.Equals(NubType.Int16))
|
||||||
case PrimitiveTypeKind.Int32:
|
{
|
||||||
_builder.AppendLine(" sub eax, ecx");
|
_builder.AppendLine(" sub ax, cx");
|
||||||
break;
|
}
|
||||||
default:
|
else if (type.Equals(NubType.Int8))
|
||||||
throw new InvalidOperationException($"Invalid type {primitiveType.Kind}");
|
{
|
||||||
|
_builder.AppendLine(" sub al, cl");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"Invalid type for subtraction {type}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GenerateBinaryMultiplication(Type type)
|
private void GenerateBinaryMultiplication(NubType type)
|
||||||
{
|
{
|
||||||
if (type is not PrimitiveType primitiveType)
|
if (type.Equals(NubType.Int64))
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("Multiplication can only be done on primitive types");
|
_builder.AppendLine(" imul rcx");
|
||||||
}
|
}
|
||||||
|
else if (type.Equals(NubType.Int32))
|
||||||
switch (primitiveType.Kind)
|
|
||||||
{
|
{
|
||||||
case PrimitiveTypeKind.Int64:
|
_builder.AppendLine(" imul ecx");
|
||||||
_builder.AppendLine(" imul rcx");
|
}
|
||||||
break;
|
else if (type.Equals(NubType.Int16))
|
||||||
case PrimitiveTypeKind.Int32:
|
{
|
||||||
_builder.AppendLine(" imul ecx");
|
_builder.AppendLine(" imul cx");
|
||||||
break;
|
}
|
||||||
default:
|
else if (type.Equals(NubType.Int8))
|
||||||
throw new InvalidOperationException($"Invalid type {primitiveType.Kind}");
|
{
|
||||||
|
_builder.AppendLine(" imul cl");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"Invalid type for multiplication {type}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GenerateBinaryDivision(Type type)
|
private void GenerateBinaryDivision(NubType type)
|
||||||
{
|
{
|
||||||
if (type is not PrimitiveType primitiveType)
|
if (type.Equals(NubType.Int64))
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("Division can only be done on primitive types");
|
_builder.AppendLine(" cqo");
|
||||||
|
_builder.AppendLine(" idiv rcx");
|
||||||
}
|
}
|
||||||
|
else if (type.Equals(NubType.Int32))
|
||||||
switch (primitiveType.Kind)
|
|
||||||
{
|
{
|
||||||
case PrimitiveTypeKind.Int64:
|
_builder.AppendLine(" cdq");
|
||||||
_builder.AppendLine(" cqo");
|
_builder.AppendLine(" idiv ecx");
|
||||||
_builder.AppendLine(" idiv rcx");
|
}
|
||||||
break;
|
else if (type.Equals(NubType.Int16))
|
||||||
case PrimitiveTypeKind.Int32:
|
{
|
||||||
_builder.AppendLine(" cdq");
|
_builder.AppendLine(" cwd");
|
||||||
_builder.AppendLine(" idiv ecx");
|
_builder.AppendLine(" idiv cx");
|
||||||
break;
|
}
|
||||||
default:
|
else if (type.Equals(NubType.Int8))
|
||||||
throw new InvalidOperationException($"Invalid type {primitiveType.Kind}");
|
{
|
||||||
|
_builder.AppendLine(" cbw");
|
||||||
|
_builder.AppendLine(" idiv cl");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"Invalid type for division {type}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -586,34 +560,22 @@ public class Generator
|
|||||||
|
|
||||||
private void GenerateLiteral(LiteralNode literal)
|
private void GenerateLiteral(LiteralNode literal)
|
||||||
{
|
{
|
||||||
switch (literal.Type)
|
if (literal.Type.Equals(NubType.String))
|
||||||
{
|
{
|
||||||
case StringType:
|
var label = _symbolTable.DefineString(literal.Literal);
|
||||||
{
|
_builder.AppendLine($" mov rax, {label}");
|
||||||
var label = _symbolTable.DefineString(literal.Literal);
|
}
|
||||||
_builder.AppendLine($" mov rax, {label}");
|
else if (literal.Type.Equals(NubType.Int64) || literal.Type.Equals(NubType.Int32) || literal.Type.Equals(NubType.Int16) || literal.Type.Equals(NubType.Int8))
|
||||||
break;
|
{
|
||||||
}
|
_builder.AppendLine($" mov rax, {literal.Literal}");
|
||||||
case PrimitiveType primitive:
|
}
|
||||||
{
|
else if (literal.Type.Equals(NubType.Bool))
|
||||||
switch (primitive.Kind)
|
{
|
||||||
{
|
_builder.AppendLine($" mov rax, {(bool.Parse(literal.Literal) ? "1" : "0")}");
|
||||||
case PrimitiveTypeKind.Bool:
|
}
|
||||||
_builder.AppendLine($" mov rax, {(bool.Parse(literal.Literal) ? "1" : "0")}");
|
else
|
||||||
break;
|
{
|
||||||
case PrimitiveTypeKind.Int64:
|
throw new NotImplementedException($"Literal type {literal.Type} not implemented");
|
||||||
_builder.AppendLine($" mov rax, {literal.Literal}");
|
|
||||||
break;
|
|
||||||
case PrimitiveTypeKind.Int32:
|
|
||||||
_builder.AppendLine($" mov rax, {literal.Literal}");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new Exception("Cannot convert literal to string");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
throw new ArgumentOutOfRangeException();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -706,31 +668,4 @@ public class Generator
|
|||||||
|
|
||||||
_builder.AppendLine(" syscall");
|
_builder.AppendLine(" syscall");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GenerateArrayIndexPointerAccess(IdentifierNode identifier, ExpressionNode index, LocalFunc func)
|
|
||||||
{
|
|
||||||
GenerateExpression(index, func);
|
|
||||||
_builder.AppendLine(" push rax");
|
|
||||||
GenerateIdentifier(identifier, func);
|
|
||||||
_builder.AppendLine(" pop rdx");
|
|
||||||
|
|
||||||
// rcx now holds the length of the array which we can use to check bounds
|
|
||||||
_builder.AppendLine(" mov rcx, [rax]");
|
|
||||||
_builder.AppendLine(" cmp rdx, rcx");
|
|
||||||
if (ZeroBasedIndexing)
|
|
||||||
{
|
|
||||||
_builder.AppendLine(" jge eb6e_oob_error");
|
|
||||||
_builder.AppendLine(" cmp rdx, 0");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_builder.AppendLine(" jg eb6e_oob_error");
|
|
||||||
_builder.AppendLine(" cmp rdx, 1");
|
|
||||||
}
|
|
||||||
_builder.AppendLine(" jl eb6e_oob_error");
|
|
||||||
|
|
||||||
_builder.AppendLine(" inc rdx");
|
|
||||||
_builder.AppendLine(" shl rdx, 3");
|
|
||||||
_builder.AppendLine(" add rax, rdx");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -118,7 +118,7 @@ public class SymbolTable
|
|||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Func ResolveFunc(string name, List<Type> parameterTypes)
|
public Func ResolveFunc(string name, List<NubType> parameterTypes)
|
||||||
{
|
{
|
||||||
var func = _funcDefinitions.FirstOrDefault(f => f.SignatureMatches(name, parameterTypes));
|
var func = _funcDefinitions.FirstOrDefault(f => f.SignatureMatches(name, parameterTypes));
|
||||||
if (func == null)
|
if (func == null)
|
||||||
@@ -129,7 +129,7 @@ public class SymbolTable
|
|||||||
return func;
|
return func;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LocalFunc ResolveLocalFunc(string name, List<Type> parameterTypes)
|
public LocalFunc ResolveLocalFunc(string name, List<NubType> parameterTypes)
|
||||||
{
|
{
|
||||||
var func = ResolveFunc(name, parameterTypes);
|
var func = ResolveFunc(name, parameterTypes);
|
||||||
if (func is not LocalFunc localFunc)
|
if (func is not LocalFunc localFunc)
|
||||||
@@ -139,7 +139,7 @@ public class SymbolTable
|
|||||||
return localFunc;
|
return localFunc;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ExternFunc ResolveExternFunc(string name, List<Type> parameterTypes)
|
public ExternFunc ResolveExternFunc(string name, List<NubType> parameterTypes)
|
||||||
{
|
{
|
||||||
var func = ResolveFunc(name, parameterTypes);
|
var func = ResolveFunc(name, parameterTypes);
|
||||||
if (func is not ExternFunc externFunc)
|
if (func is not ExternFunc externFunc)
|
||||||
@@ -161,27 +161,27 @@ public class SymbolTable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract class Variable(string name, Type type)
|
public abstract class Variable(string name, NubType type)
|
||||||
{
|
{
|
||||||
public string Name { get; } = name;
|
public string Name { get; } = name;
|
||||||
public Type Type { get; } = type;
|
public NubType Type { get; } = type;
|
||||||
|
|
||||||
public override string ToString() => $"{Name}: {Type}";
|
public override string ToString() => $"{Name}: {Type}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public class LocalVariable(string name, Type type, int offset) : Variable(name, type)
|
public class LocalVariable(string name, NubType type, int offset) : Variable(name, type)
|
||||||
{
|
{
|
||||||
public int Offset { get; } = offset;
|
public int Offset { get; } = offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class GlobalVariable(string name, Type type, string identifier) : Variable(name, type)
|
public class GlobalVariable(string name, NubType type, string identifier) : Variable(name, type)
|
||||||
{
|
{
|
||||||
public string Identifier { get; } = identifier;
|
public string Identifier { get; } = identifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract class Func
|
public abstract class Func
|
||||||
{
|
{
|
||||||
protected Func(string name, string startLabel, List<FuncParameter> parameters, Optional<Type> returnType)
|
protected Func(string name, string startLabel, List<FuncParameter> parameters, Optional<NubType> returnType)
|
||||||
{
|
{
|
||||||
Name = name;
|
Name = name;
|
||||||
Parameters = parameters;
|
Parameters = parameters;
|
||||||
@@ -192,16 +192,16 @@ public abstract class Func
|
|||||||
public string Name { get; }
|
public string Name { get; }
|
||||||
public string StartLabel { get; }
|
public string StartLabel { get; }
|
||||||
public List<FuncParameter> Parameters { get; }
|
public List<FuncParameter> Parameters { get; }
|
||||||
public Optional<Type> ReturnType { get; }
|
public Optional<NubType> ReturnType { get; }
|
||||||
|
|
||||||
public bool SignatureMatches(string name, List<Type> parameterTypes)
|
public bool SignatureMatches(string name, List<NubType> parameterTypes)
|
||||||
{
|
{
|
||||||
if (Name != name) return false;
|
if (Name != name) return false;
|
||||||
if (Parameters.Count != parameterTypes.Count) return false;
|
if (Parameters.Count != parameterTypes.Count) return false;
|
||||||
|
|
||||||
for (var i = 0; i < parameterTypes.Count; i++)
|
for (var i = 0; i < parameterTypes.Count; i++)
|
||||||
{
|
{
|
||||||
if (!Parameters[i].Type.IsAssignableTo(parameterTypes[i])) return false;
|
if (!Parameters[i].Type.Equals(parameterTypes[i])) return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -212,14 +212,14 @@ public abstract class Func
|
|||||||
|
|
||||||
public class ExternFunc : Func
|
public class ExternFunc : Func
|
||||||
{
|
{
|
||||||
public ExternFunc(string name, string startLabel, List<FuncParameter> parameters, Optional<Type> returnType) : base(name, startLabel, parameters, returnType)
|
public ExternFunc(string name, string startLabel, List<FuncParameter> parameters, Optional<NubType> returnType) : base(name, startLabel, parameters, returnType)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class LocalFunc : Func
|
public class LocalFunc : Func
|
||||||
{
|
{
|
||||||
public LocalFunc(string name, string startLabel, string endLabel, List<FuncParameter> parameters, Optional<Type> returnType, List<Variable> variables) : base(name, startLabel, parameters, returnType)
|
public LocalFunc(string name, string startLabel, string endLabel, List<FuncParameter> parameters, Optional<NubType> returnType, List<Variable> variables) : base(name, startLabel, parameters, returnType)
|
||||||
{
|
{
|
||||||
EndLabel = endLabel;
|
EndLabel = endLabel;
|
||||||
Variables = variables;
|
Variables = variables;
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ public class Lexer
|
|||||||
|
|
||||||
if (buffer is "true" or "false")
|
if (buffer is "true" or "false")
|
||||||
{
|
{
|
||||||
return new LiteralToken(new PrimitiveType(PrimitiveTypeKind.Bool), buffer);
|
return new LiteralToken(NubType.Bool, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new IdentifierToken(buffer);
|
return new IdentifierToken(buffer);
|
||||||
@@ -103,7 +103,7 @@ public class Lexer
|
|||||||
current = Peek();
|
current = Peek();
|
||||||
}
|
}
|
||||||
|
|
||||||
return new LiteralToken(new PrimitiveType(PrimitiveTypeKind.Int64), buffer);
|
return new LiteralToken(NubType.Int64, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Revisit this
|
// TODO: Revisit this
|
||||||
@@ -148,7 +148,7 @@ public class Lexer
|
|||||||
buffer += current.Value;
|
buffer += current.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new LiteralToken(new StringType(), buffer);
|
return new LiteralToken(NubType.String, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (char.IsWhiteSpace(current.Value))
|
if (char.IsWhiteSpace(current.Value))
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
namespace Nub.Lang.Frontend.Lexing;
|
namespace Nub.Lang.Frontend.Lexing;
|
||||||
|
|
||||||
public class LiteralToken(Type type, string value) : Token
|
public class LiteralToken(NubType type, string value) : Token
|
||||||
{
|
{
|
||||||
public Type Type { get; } = type;
|
public NubType Type { get; } = type;
|
||||||
public string Value { get; } = value;
|
public string Value { get; } = value;
|
||||||
}
|
}
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
namespace Nub.Lang.Frontend.Parsing;
|
|
||||||
|
|
||||||
public class ArrayIndexAccessNode(IdentifierNode identifier, ExpressionNode index) : ExpressionNode
|
|
||||||
{
|
|
||||||
public IdentifierNode Identifier { get; } = identifier;
|
|
||||||
public ExpressionNode Index { get; } = index;
|
|
||||||
|
|
||||||
public override string ToString() => $"{Identifier}[{Index}]";
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
namespace Nub.Lang.Frontend.Parsing;
|
|
||||||
|
|
||||||
public class ArrayIndexAssignmentNode(IdentifierNode identifier, ExpressionNode index, ExpressionNode value) : StatementNode
|
|
||||||
{
|
|
||||||
public IdentifierNode Identifier { get; } = identifier;
|
|
||||||
public ExpressionNode Index { get; } = index;
|
|
||||||
public ExpressionNode Value { get; } = value;
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
namespace Nub.Lang.Frontend.Parsing;
|
|
||||||
|
|
||||||
public class ArrayInitializerNode(long length, Type innerType) : ExpressionNode
|
|
||||||
{
|
|
||||||
public long Length { get; } = length;
|
|
||||||
public Type InnerType { get; } = innerType;
|
|
||||||
}
|
|
||||||
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
public abstract class ExpressionNode : Node
|
public abstract class ExpressionNode : Node
|
||||||
{
|
{
|
||||||
private Type? _type;
|
private NubType? _type;
|
||||||
public Type Type
|
public NubType Type
|
||||||
{
|
{
|
||||||
get => _type ?? throw new Exception("Tried to access expression type before type was populated");
|
get => _type ?? throw new Exception("Tried to access expression type before type was populated");
|
||||||
set => _type = value;
|
set => _type = value;
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
namespace Nub.Lang.Frontend.Parsing;
|
namespace Nub.Lang.Frontend.Parsing;
|
||||||
|
|
||||||
public class ExternFuncDefinitionNode(string name, List<FuncParameter> parameters, Optional<Type> returnType) : DefinitionNode
|
public class ExternFuncDefinitionNode(string name, List<FuncParameter> parameters, Optional<NubType> returnType) : DefinitionNode
|
||||||
{
|
{
|
||||||
public string Name { get; } = name;
|
public string Name { get; } = name;
|
||||||
public List<FuncParameter> Parameters { get; } = parameters;
|
public List<FuncParameter> Parameters { get; } = parameters;
|
||||||
public Optional<Type> ReturnType { get; } = returnType;
|
public Optional<NubType> ReturnType { get; } = returnType;
|
||||||
|
|
||||||
public override string ToString() => $"{Name}({string.Join(", ", Parameters.Select(p => p.ToString()))}){(ReturnType.HasValue ? ": " + ReturnType.Value : "")}";
|
public override string ToString() => $"{Name}({string.Join(", ", Parameters.Select(p => p.ToString()))}){(ReturnType.HasValue ? ": " + ReturnType.Value : "")}";
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
namespace Nub.Lang.Frontend.Parsing;
|
namespace Nub.Lang.Frontend.Parsing;
|
||||||
|
|
||||||
public class LiteralNode(string literal, Type type) : ExpressionNode
|
public class LiteralNode(string literal, NubType type) : ExpressionNode
|
||||||
{
|
{
|
||||||
public string Literal { get; } = literal;
|
public string Literal { get; } = literal;
|
||||||
public Type LiteralType { get; } = type;
|
public NubType LiteralType { get; } = type;
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
namespace Nub.Lang.Frontend.Parsing;
|
namespace Nub.Lang.Frontend.Parsing;
|
||||||
|
|
||||||
public class LocalFuncDefinitionNode(string name, List<FuncParameter> parameters, BlockNode body, Optional<Type> returnType) : DefinitionNode
|
public class LocalFuncDefinitionNode(string name, List<FuncParameter> parameters, BlockNode body, Optional<NubType> returnType) : DefinitionNode
|
||||||
{
|
{
|
||||||
public string Name { get; } = name;
|
public string Name { get; } = name;
|
||||||
public List<FuncParameter> Parameters { get; } = parameters;
|
public List<FuncParameter> Parameters { get; } = parameters;
|
||||||
public BlockNode Body { get; } = body;
|
public BlockNode Body { get; } = body;
|
||||||
public Optional<Type> ReturnType { get; } = returnType;
|
public Optional<NubType> ReturnType { get; } = returnType;
|
||||||
|
|
||||||
public override string ToString() => $"{Name}({string.Join(", ", Parameters.Select(p => p.ToString()))}){(ReturnType.HasValue ? ": " + ReturnType.Value : "")}";
|
public override string ToString() => $"{Name}({string.Join(", ", Parameters.Select(p => p.ToString()))}){(ReturnType.HasValue ? ": " + ReturnType.Value : "")}";
|
||||||
}
|
}
|
||||||
@@ -7,21 +7,21 @@ public class Parser
|
|||||||
{
|
{
|
||||||
private List<Token> _tokens = [];
|
private List<Token> _tokens = [];
|
||||||
private int _index;
|
private int _index;
|
||||||
|
|
||||||
public ModuleNode ParseModule(List<Token> tokens, string path)
|
public ModuleNode ParseModule(List<Token> tokens, string path)
|
||||||
{
|
{
|
||||||
_index = 0;
|
_index = 0;
|
||||||
_tokens = tokens;
|
_tokens = tokens;
|
||||||
|
|
||||||
List<DefinitionNode> definitions = [];
|
List<DefinitionNode> definitions = [];
|
||||||
List<string> imports = [];
|
List<string> imports = [];
|
||||||
|
|
||||||
while (Peek().HasValue)
|
while (Peek().HasValue)
|
||||||
{
|
{
|
||||||
if (TryExpectSymbol(Symbol.Import))
|
if (TryExpectSymbol(Symbol.Import))
|
||||||
{
|
{
|
||||||
var name = ExpectLiteral();
|
var name = ExpectLiteral();
|
||||||
if (name.Type is not StringType)
|
if (!name.Type.Equals(NubType.String))
|
||||||
{
|
{
|
||||||
throw new Exception("Import statements must have a string literal value");
|
throw new Exception("Import statements must have a string literal value");
|
||||||
}
|
}
|
||||||
@@ -75,10 +75,10 @@ public class Parser
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var returnType = Optional<Type>.Empty();
|
var returnType = Optional<NubType>.Empty();
|
||||||
if (TryExpectSymbol(Symbol.Colon))
|
if (TryExpectSymbol(Symbol.Colon))
|
||||||
{
|
{
|
||||||
returnType = ParseType();
|
returnType = ParseTypeInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
var body = ParseBlock();
|
var body = ParseBlock();
|
||||||
@@ -101,14 +101,14 @@ public class Parser
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var returnType = Optional<Type>.Empty();
|
var returnType = Optional<NubType>.Empty();
|
||||||
if (TryExpectSymbol(Symbol.Colon))
|
if (TryExpectSymbol(Symbol.Colon))
|
||||||
{
|
{
|
||||||
returnType = ParseType();
|
returnType = ParseTypeInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
ExpectSymbol(Symbol.Semicolon);
|
ExpectSymbol(Symbol.Semicolon);
|
||||||
|
|
||||||
return new ExternFuncDefinitionNode(name.Value, parameters, returnType);
|
return new ExternFuncDefinitionNode(name.Value, parameters, returnType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,28 +117,27 @@ public class Parser
|
|||||||
var name = ExpectIdentifier().Value;
|
var name = ExpectIdentifier().Value;
|
||||||
|
|
||||||
ExpectSymbol(Symbol.OpenBrace);
|
ExpectSymbol(Symbol.OpenBrace);
|
||||||
|
|
||||||
List<StructMember> variables = [];
|
List<StructMember> variables = [];
|
||||||
|
|
||||||
while (!TryExpectSymbol(Symbol.CloseBrace))
|
while (!TryExpectSymbol(Symbol.CloseBrace))
|
||||||
{
|
{
|
||||||
ExpectSymbol(Symbol.Let);
|
|
||||||
var variableName = ExpectIdentifier().Value;
|
var variableName = ExpectIdentifier().Value;
|
||||||
ExpectSymbol(Symbol.Colon);
|
ExpectSymbol(Symbol.Colon);
|
||||||
var variableType = ParseType();
|
var variableType = ParseTypeInstance();
|
||||||
|
|
||||||
var variableValue = Optional<ExpressionNode>.Empty();
|
var variableValue = Optional<ExpressionNode>.Empty();
|
||||||
|
|
||||||
if (TryExpectSymbol(Symbol.Assign))
|
if (TryExpectSymbol(Symbol.Assign))
|
||||||
{
|
{
|
||||||
variableValue = ParseExpression();
|
variableValue = ParseExpression();
|
||||||
}
|
}
|
||||||
|
|
||||||
ExpectSymbol(Symbol.Semicolon);
|
ExpectSymbol(Symbol.Semicolon);
|
||||||
|
|
||||||
variables.Add(new StructMember(variableName, variableType, variableValue));
|
variables.Add(new StructMember(variableName, variableType, variableValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
return new StructDefinitionNode(name, variables);
|
return new StructDefinitionNode(name, variables);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,7 +145,7 @@ public class Parser
|
|||||||
{
|
{
|
||||||
var name = ExpectIdentifier();
|
var name = ExpectIdentifier();
|
||||||
ExpectSymbol(Symbol.Colon);
|
ExpectSymbol(Symbol.Colon);
|
||||||
var type = ParseType();
|
var type = ParseTypeInstance();
|
||||||
|
|
||||||
return new FuncParameter(name.Value, type);
|
return new FuncParameter(name.Value, type);
|
||||||
}
|
}
|
||||||
@@ -179,15 +178,6 @@ public class Parser
|
|||||||
|
|
||||||
return new FuncCallStatementNode(new FuncCall(identifier.Value, parameters));
|
return new FuncCallStatementNode(new FuncCall(identifier.Value, parameters));
|
||||||
}
|
}
|
||||||
case Symbol.OpenBracket:
|
|
||||||
{
|
|
||||||
var index = ParseExpression();
|
|
||||||
ExpectSymbol(Symbol.CloseBracket);
|
|
||||||
ExpectSymbol(Symbol.Assign);
|
|
||||||
var value = ParseExpression();
|
|
||||||
ExpectSymbol(Symbol.Semicolon);
|
|
||||||
return new ArrayIndexAssignmentNode(new IdentifierNode(identifier.Value), index, value);
|
|
||||||
}
|
|
||||||
case Symbol.Assign:
|
case Symbol.Assign:
|
||||||
{
|
{
|
||||||
var value = ParseExpression();
|
var value = ParseExpression();
|
||||||
@@ -238,7 +228,7 @@ public class Parser
|
|||||||
ExpectSymbol(Symbol.Assign);
|
ExpectSymbol(Symbol.Assign);
|
||||||
var value = ParseExpression();
|
var value = ParseExpression();
|
||||||
ExpectSymbol(Symbol.Semicolon);
|
ExpectSymbol(Symbol.Semicolon);
|
||||||
|
|
||||||
return new VariableAssignmentNode(name, value);
|
return new VariableAssignmentNode(name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -254,7 +244,7 @@ public class Parser
|
|||||||
? (Variant<IfNode, BlockNode>)ParseIf()
|
? (Variant<IfNode, BlockNode>)ParseIf()
|
||||||
: (Variant<IfNode, BlockNode>)ParseBlock();
|
: (Variant<IfNode, BlockNode>)ParseBlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
return new IfNode(condition, body, elseStatement);
|
return new IfNode(condition, body, elseStatement);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -276,7 +266,7 @@ public class Parser
|
|||||||
ExpectSymbol(Symbol.Semicolon);
|
ExpectSymbol(Symbol.Semicolon);
|
||||||
return new ContinueNode();
|
return new ContinueNode();
|
||||||
}
|
}
|
||||||
|
|
||||||
private ExpressionNode ParseExpression(int precedence = 0)
|
private ExpressionNode ParseExpression(int precedence = 0)
|
||||||
{
|
{
|
||||||
var left = ParsePrimaryExpression();
|
var left = ParsePrimaryExpression();
|
||||||
@@ -284,15 +274,16 @@ public class Parser
|
|||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
var token = Peek();
|
var token = Peek();
|
||||||
if (!token.HasValue || token.Value is not SymbolToken symbolToken || !TryGetBinaryOperator(symbolToken.Symbol, out var op) || GetBinaryOperatorPrecedence(op.Value) < precedence)
|
if (!token.HasValue || token.Value is not SymbolToken symbolToken || !TryGetBinaryOperator(symbolToken.Symbol, out var op) ||
|
||||||
|
GetBinaryOperatorPrecedence(op.Value) < precedence)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
Next();
|
Next();
|
||||||
var right = ParseExpression(GetBinaryOperatorPrecedence(op.Value) + 1);
|
var right = ParseExpression(GetBinaryOperatorPrecedence(op.Value) + 1);
|
||||||
|
|
||||||
left = new BinaryExpressionNode(left, op.Value, right);
|
left = new BinaryExpressionNode(left, op.Value, right);
|
||||||
}
|
}
|
||||||
|
|
||||||
return left;
|
return left;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -360,9 +351,13 @@ public class Parser
|
|||||||
switch (token)
|
switch (token)
|
||||||
{
|
{
|
||||||
case LiteralToken literal:
|
case LiteralToken literal:
|
||||||
|
{
|
||||||
return new LiteralNode(literal.Value, literal.Type);
|
return new LiteralNode(literal.Value, literal.Type);
|
||||||
|
}
|
||||||
case IdentifierToken identifier:
|
case IdentifierToken identifier:
|
||||||
|
{
|
||||||
return ParseExpressionIdentifier(identifier);
|
return ParseExpressionIdentifier(identifier);
|
||||||
|
}
|
||||||
case SymbolToken symbolToken:
|
case SymbolToken symbolToken:
|
||||||
{
|
{
|
||||||
switch (symbolToken.Symbol)
|
switch (symbolToken.Symbol)
|
||||||
@@ -375,45 +370,25 @@ public class Parser
|
|||||||
}
|
}
|
||||||
case Symbol.New:
|
case Symbol.New:
|
||||||
{
|
{
|
||||||
var type = ParseType();
|
var type = ParseTypeInstance();
|
||||||
switch (type)
|
Dictionary<string, ExpressionNode> initializers = [];
|
||||||
|
ExpectSymbol(Symbol.OpenBrace);
|
||||||
|
while (!TryExpectSymbol(Symbol.CloseBrace))
|
||||||
{
|
{
|
||||||
case ArrayType:
|
var name = ExpectIdentifier().Value;
|
||||||
{
|
ExpectSymbol(Symbol.Assign);
|
||||||
ExpectSymbol(Symbol.OpenParen);
|
var value = ParseExpression();
|
||||||
var size = ExpectLiteral();
|
TryExpectSymbol(Symbol.Semicolon);
|
||||||
if (size.Type is not PrimitiveType { Kind: PrimitiveTypeKind.Int64 })
|
initializers.Add(name, value);
|
||||||
{
|
|
||||||
throw new Exception($"Array initializer size must be an {PrimitiveTypeKind.Int64}");
|
|
||||||
}
|
|
||||||
ExpectSymbol(Symbol.CloseParen);
|
|
||||||
|
|
||||||
return new ArrayInitializerNode(long.Parse(size.Value), type);
|
|
||||||
}
|
|
||||||
case StructType structType:
|
|
||||||
{
|
|
||||||
Dictionary<string, ExpressionNode> initializers = [];
|
|
||||||
ExpectSymbol(Symbol.OpenBrace);
|
|
||||||
while (!TryExpectSymbol(Symbol.CloseBrace))
|
|
||||||
{
|
|
||||||
var name = ExpectIdentifier().Value;
|
|
||||||
ExpectSymbol(Symbol.Assign);
|
|
||||||
var value = ParseExpression();
|
|
||||||
TryExpectSymbol(Symbol.Comma);
|
|
||||||
initializers.Add(name, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new StructInitializerNode(structType, initializers);
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
throw new Exception($"Type {type} cannot be initialized with the new keyword");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return new StructInitializerNode(type, initializers);
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
throw new Exception($"Unknown symbol: {symbolToken.Symbol}");
|
throw new Exception($"Unknown symbol: {symbolToken.Symbol}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
throw new Exception($"Unexpected token type {token.GetType().Name}");
|
throw new Exception($"Unexpected token type {token.GetType().Name}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -448,13 +423,6 @@ public class Parser
|
|||||||
|
|
||||||
return new StructMemberAccessorNode(members);
|
return new StructMemberAccessorNode(members);
|
||||||
}
|
}
|
||||||
case Symbol.OpenBracket:
|
|
||||||
{
|
|
||||||
Next();
|
|
||||||
var index = ParseExpression();
|
|
||||||
ExpectSymbol(Symbol.CloseBracket);
|
|
||||||
return new ArrayIndexAccessNode(new IdentifierNode(identifier.Value), index);
|
|
||||||
}
|
|
||||||
case Symbol.OpenParen:
|
case Symbol.OpenParen:
|
||||||
{
|
{
|
||||||
Next();
|
Next();
|
||||||
@@ -473,10 +441,11 @@ public class Parser
|
|||||||
return new FuncCallExpressionNode(new FuncCall(identifier.Value, parameters));
|
return new FuncCallExpressionNode(new FuncCall(identifier.Value, parameters));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new IdentifierNode(identifier.Value);
|
return new IdentifierNode(identifier.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -492,36 +461,22 @@ public class Parser
|
|||||||
return new BlockNode(statements);
|
return new BlockNode(statements);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Type ParseType()
|
private NubType ParseTypeInstance()
|
||||||
{
|
{
|
||||||
|
var parameters = new List<NubType>();
|
||||||
var name = ExpectIdentifier().Value;
|
var name = ExpectIdentifier().Value;
|
||||||
switch (name)
|
|
||||||
|
if (TryExpectSymbol(Symbol.LessThan))
|
||||||
{
|
{
|
||||||
case "String":
|
do
|
||||||
{
|
{
|
||||||
return new StringType();
|
parameters.Add(ParseTypeInstance());
|
||||||
}
|
} while (TryExpectSymbol(Symbol.Comma));
|
||||||
case "Array":
|
|
||||||
{
|
ExpectSymbol(Symbol.GreaterThan);
|
||||||
ExpectSymbol(Symbol.LessThan);
|
|
||||||
var innerType = ParseType();
|
|
||||||
ExpectSymbol(Symbol.GreaterThan);
|
|
||||||
return new ArrayType(innerType);
|
|
||||||
}
|
|
||||||
case "Any":
|
|
||||||
{
|
|
||||||
return new AnyType();
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
if (PrimitiveType.TryParse(name, out var primitiveType))
|
|
||||||
{
|
|
||||||
return primitiveType;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new StructType(name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return new NubType(name, parameters.ToArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Token ExpectToken()
|
private Token ExpectToken()
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
namespace Nub.Lang.Frontend.Parsing;
|
namespace Nub.Lang.Frontend.Parsing;
|
||||||
|
|
||||||
public class StructInitializerNode(StructType structType, Dictionary<string, ExpressionNode> initializers) : ExpressionNode
|
public class StructInitializerNode(NubType structType, Dictionary<string, ExpressionNode> initializers) : ExpressionNode
|
||||||
{
|
{
|
||||||
public StructType StructType { get; } = structType;
|
public NubType StructType { get; } = structType;
|
||||||
public Dictionary<string, ExpressionNode> Initializers { get; } = initializers;
|
public Dictionary<string, ExpressionNode> Initializers { get; } = initializers;
|
||||||
}
|
}
|
||||||
@@ -2,12 +2,12 @@
|
|||||||
|
|
||||||
namespace Nub.Lang.Frontend.Typing;
|
namespace Nub.Lang.Frontend.Typing;
|
||||||
|
|
||||||
public class Func(string name, List<FuncParameter> parameters, Optional<BlockNode> body, Optional<Type> returnType)
|
public class Func(string name, List<FuncParameter> parameters, Optional<BlockNode> body, Optional<NubType> returnType)
|
||||||
{
|
{
|
||||||
public string Name { get; } = name;
|
public string Name { get; } = name;
|
||||||
public List<FuncParameter> Parameters { get; } = parameters;
|
public List<FuncParameter> Parameters { get; } = parameters;
|
||||||
public Optional<BlockNode> Body { get; } = body;
|
public Optional<BlockNode> Body { get; } = body;
|
||||||
public Optional<Type> ReturnType { get; } = returnType;
|
public Optional<NubType> ReturnType { get; } = returnType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ExpressionTyper
|
public class ExpressionTyper
|
||||||
@@ -96,9 +96,6 @@ public class ExpressionTyper
|
|||||||
{
|
{
|
||||||
switch (statement)
|
switch (statement)
|
||||||
{
|
{
|
||||||
case ArrayIndexAssignmentNode arrayIndexAssignment:
|
|
||||||
PopulateArrayIndexAssignment(arrayIndexAssignment);
|
|
||||||
break;
|
|
||||||
case BreakNode:
|
case BreakNode:
|
||||||
case ContinueNode:
|
case ContinueNode:
|
||||||
break;
|
break;
|
||||||
@@ -128,13 +125,6 @@ public class ExpressionTyper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PopulateArrayIndexAssignment(ArrayIndexAssignmentNode arrayIndexAssignment)
|
|
||||||
{
|
|
||||||
PopulateIdentifier(arrayIndexAssignment.Identifier);
|
|
||||||
PopulateExpression(arrayIndexAssignment.Index);
|
|
||||||
PopulateExpression(arrayIndexAssignment.Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void PopulateFuncCallStatement(FuncCallStatementNode funcCall)
|
private void PopulateFuncCallStatement(FuncCallStatementNode funcCall)
|
||||||
{
|
{
|
||||||
foreach (var parameter in funcCall.FuncCall.Parameters)
|
foreach (var parameter in funcCall.FuncCall.Parameters)
|
||||||
@@ -194,12 +184,6 @@ public class ExpressionTyper
|
|||||||
{
|
{
|
||||||
switch (expression)
|
switch (expression)
|
||||||
{
|
{
|
||||||
case ArrayIndexAccessNode arrayIndexAccess:
|
|
||||||
PopulateArrayIndexAccess(arrayIndexAccess);
|
|
||||||
break;
|
|
||||||
case ArrayInitializerNode arrayInitializer:
|
|
||||||
PopulateArrayInitializer(arrayInitializer);
|
|
||||||
break;
|
|
||||||
case BinaryExpressionNode binaryExpression:
|
case BinaryExpressionNode binaryExpression:
|
||||||
PopulateBinaryExpression(binaryExpression);
|
PopulateBinaryExpression(binaryExpression);
|
||||||
break;
|
break;
|
||||||
@@ -226,30 +210,6 @@ public class ExpressionTyper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PopulateArrayIndexAccess(ArrayIndexAccessNode arrayIndexAccess)
|
|
||||||
{
|
|
||||||
PopulateExpression(arrayIndexAccess.Index);
|
|
||||||
PopulateIdentifier(arrayIndexAccess.Identifier);
|
|
||||||
|
|
||||||
var variable = _variables.FirstOrDefault(v => v.Name == arrayIndexAccess.Identifier.Identifier);
|
|
||||||
if (variable == null)
|
|
||||||
{
|
|
||||||
throw new Exception($"Variable {arrayIndexAccess.Identifier} is not defined");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (variable.Type is not ArrayType arrayType)
|
|
||||||
{
|
|
||||||
throw new Exception($"Variable {arrayIndexAccess.Identifier} is not an array type");
|
|
||||||
}
|
|
||||||
|
|
||||||
arrayIndexAccess.Type = arrayType.InnerType;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void PopulateArrayInitializer(ArrayInitializerNode arrayInitializer)
|
|
||||||
{
|
|
||||||
arrayInitializer.Type = arrayInitializer.InnerType;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void PopulateBinaryExpression(BinaryExpressionNode binaryExpression)
|
private void PopulateBinaryExpression(BinaryExpressionNode binaryExpression)
|
||||||
{
|
{
|
||||||
PopulateExpression(binaryExpression.Left);
|
PopulateExpression(binaryExpression.Left);
|
||||||
@@ -263,7 +223,7 @@ public class ExpressionTyper
|
|||||||
case BinaryExpressionOperator.LessThan:
|
case BinaryExpressionOperator.LessThan:
|
||||||
case BinaryExpressionOperator.LessThanOrEqual:
|
case BinaryExpressionOperator.LessThanOrEqual:
|
||||||
{
|
{
|
||||||
binaryExpression.Type = new PrimitiveType(PrimitiveTypeKind.Bool);
|
binaryExpression.Type = new NubType("bool", []);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case BinaryExpressionOperator.Plus:
|
case BinaryExpressionOperator.Plus:
|
||||||
@@ -333,13 +293,8 @@ public class ExpressionTyper
|
|||||||
{
|
{
|
||||||
throw new Exception($"Variable {structMemberAccessor.Members[0]} is not defined");
|
throw new Exception($"Variable {structMemberAccessor.Members[0]} is not defined");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (variable.Type is not StructType variableType)
|
|
||||||
{
|
|
||||||
throw new Exception("Variable " + structMemberAccessor.Members[0] + " is not a struct");
|
|
||||||
}
|
|
||||||
|
|
||||||
var definition = _structDefinitions.FirstOrDefault(sd => sd.Name == variableType.Name);
|
var definition = _structDefinitions.FirstOrDefault(sd => sd.Name == variable.Type.Name);
|
||||||
if (definition == null)
|
if (definition == null)
|
||||||
{
|
{
|
||||||
throw new Exception($"Struct {structMemberAccessor.Members[0]} is not defined");
|
throw new Exception($"Struct {structMemberAccessor.Members[0]} is not defined");
|
||||||
@@ -352,13 +307,8 @@ public class ExpressionTyper
|
|||||||
{
|
{
|
||||||
throw new Exception($"Member {structMemberAccessor.Members[i]} does not exist on struct {definition.Name}");
|
throw new Exception($"Member {structMemberAccessor.Members[i]} does not exist on struct {definition.Name}");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (member.Type is not StructType memberType)
|
|
||||||
{
|
|
||||||
throw new Exception($"Member {structMemberAccessor.Members[i]} on struct {definition.Name} is not a struct");
|
|
||||||
}
|
|
||||||
|
|
||||||
definition = _structDefinitions.FirstOrDefault(sd => sd.Name == memberType.Name);
|
definition = _structDefinitions.FirstOrDefault(sd => sd.Name == member.Type.Name);
|
||||||
if (definition == null)
|
if (definition == null)
|
||||||
{
|
{
|
||||||
throw new Exception($"Struct {structMemberAccessor.Members[i]} is not defined");
|
throw new Exception($"Struct {structMemberAccessor.Members[i]} is not defined");
|
||||||
@@ -381,12 +331,12 @@ public class ExpressionTyper
|
|||||||
PopulateExpression(parameter);
|
PopulateExpression(parameter);
|
||||||
}
|
}
|
||||||
|
|
||||||
syscall.Type = new PrimitiveType(PrimitiveTypeKind.Int64);
|
syscall.Type = new NubType("int64", []);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class Variable(string name, Type type)
|
private class Variable(string name, NubType type)
|
||||||
{
|
{
|
||||||
public string Name { get; } = name;
|
public string Name { get; } = name;
|
||||||
public Type Type { get; } = type;
|
public NubType Type { get; } = type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
namespace Nub.Lang;
|
namespace Nub.Lang;
|
||||||
|
|
||||||
public class FuncParameter(string name, Type type)
|
public class FuncParameter(string name, NubType type)
|
||||||
{
|
{
|
||||||
public string Name { get; } = name;
|
public string Name { get; } = name;
|
||||||
public Type Type { get; } = type;
|
public NubType Type { get; } = type;
|
||||||
|
|
||||||
public override string ToString() => $"{Name}: {Type}";
|
public override string ToString() => $"{Name}: {Type}";
|
||||||
}
|
}
|
||||||
41
lang/Nub.Lang/NubType.cs
Normal file
41
lang/Nub.Lang/NubType.cs
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
namespace Nub.Lang;
|
||||||
|
|
||||||
|
public sealed class NubType
|
||||||
|
{
|
||||||
|
public NubType(string name, NubType[] generics)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
Generics = generics;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Name { get; }
|
||||||
|
public NubType[] Generics { get; }
|
||||||
|
|
||||||
|
public static NubType Int64 => new("int64", []);
|
||||||
|
public static NubType Int32 => new("int32", []);
|
||||||
|
public static NubType Int16 => new("int16", []);
|
||||||
|
public static NubType Int8 => new("int8", []);
|
||||||
|
public static NubType Bool => new("bool", []);
|
||||||
|
public static NubType String => new("string", []);
|
||||||
|
public static NubType Array(NubType innerType) => new("array", [innerType]);
|
||||||
|
|
||||||
|
public override bool Equals(object? obj)
|
||||||
|
{
|
||||||
|
if (obj is not NubType item)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Name.Equals(item.Name) && Generics.SequenceEqual(item.Generics);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return HashCode.Combine(Name, Generics);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"{Name}<{string.Join(", ", Generics.Select(x => x.ToString()))}>";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
namespace Nub.Lang;
|
namespace Nub.Lang;
|
||||||
|
|
||||||
public class StructMember(string name, Type type, Optional<ExpressionNode> value)
|
public class StructMember(string name, NubType type, Optional<ExpressionNode> value)
|
||||||
{
|
{
|
||||||
public string Name { get; } = name;
|
public string Name { get; } = name;
|
||||||
public Type Type { get; } = type;
|
public NubType Type { get; } = type;
|
||||||
public Optional<ExpressionNode> Value { get; } = value;
|
public Optional<ExpressionNode> Value { get; } = value;
|
||||||
}
|
}
|
||||||
@@ -1,114 +0,0 @@
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
|
|
||||||
namespace Nub.Lang;
|
|
||||||
|
|
||||||
public abstract class Type
|
|
||||||
{
|
|
||||||
public virtual bool IsAssignableTo(Type otherType)
|
|
||||||
{
|
|
||||||
return this == otherType || otherType is AnyType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Equals(object? obj)
|
|
||||||
{
|
|
||||||
if (ReferenceEquals(this, obj)) return true;
|
|
||||||
if (obj is not Type otherType) return false;
|
|
||||||
return Equals(otherType);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract bool Equals(Type other);
|
|
||||||
public abstract override int GetHashCode();
|
|
||||||
|
|
||||||
public static bool operator == (Type? left, Type? right)
|
|
||||||
{
|
|
||||||
if (left is null && right is null) return true;
|
|
||||||
if (left is null || right is null) return false;
|
|
||||||
return ReferenceEquals(left, right) || left.Equals(right);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool operator !=(Type? left, Type? right) => !(left == right);
|
|
||||||
}
|
|
||||||
|
|
||||||
public class AnyType : Type
|
|
||||||
{
|
|
||||||
protected override bool Equals(Type other) => other is AnyType;
|
|
||||||
public override int GetHashCode() => nameof(AnyType).GetHashCode();
|
|
||||||
public override string ToString() => "Any";
|
|
||||||
}
|
|
||||||
|
|
||||||
public class PrimitiveType(PrimitiveTypeKind kind) : Type
|
|
||||||
{
|
|
||||||
// TODO: This should be looked at more in the future
|
|
||||||
public override bool IsAssignableTo(Type otherType)
|
|
||||||
{
|
|
||||||
if (base.IsAssignableTo(otherType)) return true;
|
|
||||||
|
|
||||||
if (otherType is PrimitiveType otherPrimitive)
|
|
||||||
{
|
|
||||||
return (Kind, otherPrimitive.Kind) switch
|
|
||||||
{
|
|
||||||
(PrimitiveTypeKind.Int32, PrimitiveTypeKind.Int64) => true,
|
|
||||||
_ => false
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool TryParse(string value, [NotNullWhen(true)] out PrimitiveType? result)
|
|
||||||
{
|
|
||||||
result = value switch
|
|
||||||
{
|
|
||||||
"bool" => new PrimitiveType(PrimitiveTypeKind.Bool),
|
|
||||||
"int64" => new PrimitiveType(PrimitiveTypeKind.Int64),
|
|
||||||
"int32" => new PrimitiveType(PrimitiveTypeKind.Int32),
|
|
||||||
_ => null
|
|
||||||
};
|
|
||||||
|
|
||||||
return result != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PrimitiveTypeKind Kind { get; } = kind;
|
|
||||||
|
|
||||||
protected override bool Equals(Type other) => other is PrimitiveType primitiveType && Kind == primitiveType.Kind;
|
|
||||||
public override int GetHashCode() => Kind.GetHashCode();
|
|
||||||
public override string ToString() => Kind.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum PrimitiveTypeKind
|
|
||||||
{
|
|
||||||
Bool,
|
|
||||||
Int64,
|
|
||||||
Int32,
|
|
||||||
}
|
|
||||||
|
|
||||||
public class StringType : Type
|
|
||||||
{
|
|
||||||
protected override bool Equals(Type other) => other is StringType;
|
|
||||||
public override int GetHashCode() => nameof(StringType).GetHashCode();
|
|
||||||
public override string ToString() => "String";
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ArrayType(Type innerType) : Type
|
|
||||||
{
|
|
||||||
public Type InnerType { get; } = innerType;
|
|
||||||
|
|
||||||
public override bool IsAssignableTo(Type otherType)
|
|
||||||
{
|
|
||||||
if (otherType is ArrayType arrayType && arrayType.InnerType.IsAssignableTo(InnerType)) return true;
|
|
||||||
return base.IsAssignableTo(otherType);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override bool Equals(Type other) => other is ArrayType at && InnerType.Equals(at.InnerType);
|
|
||||||
public override int GetHashCode() => HashCode.Combine(InnerType);
|
|
||||||
public override string ToString() => $"Array<{InnerType}>";
|
|
||||||
}
|
|
||||||
|
|
||||||
public class StructType(string name) : Type
|
|
||||||
{
|
|
||||||
public string Name { get; } = name;
|
|
||||||
|
|
||||||
protected override bool Equals(Type other) => other is StructType classType && Name == classType.Name;
|
|
||||||
public override int GetHashCode() => Name.GetHashCode();
|
|
||||||
public override string ToString() => Name;
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
global arr_size
|
|
||||||
|
|
||||||
section .text
|
|
||||||
arr_size:
|
|
||||||
mov rax, [rdi]
|
|
||||||
ret
|
|
||||||
Reference in New Issue
Block a user