...
This commit is contained in:
@@ -94,14 +94,14 @@ public sealed class BoundDefinitionTable
|
||||
return structNode.Fields.First(x => x.Name == field);
|
||||
}
|
||||
|
||||
public IEnumerable<BoundTraitImplNode> LookupTraitImpls(BoundNubType itemType)
|
||||
public IEnumerable<BoundTraitImplNode> LookupTraitImpls(NubType itemType)
|
||||
{
|
||||
return _topLevelNodes
|
||||
.OfType<BoundTraitImplNode>()
|
||||
.Where(x => x.ForType == itemType);
|
||||
}
|
||||
|
||||
public BoundTraitFuncImplNode LookupTraitFuncImpl(BoundNubType forType, string name)
|
||||
public BoundTraitFuncImplNode LookupTraitFuncImpl(NubType forType, string name)
|
||||
{
|
||||
return _topLevelNodes
|
||||
.OfType<BoundTraitImplNode>()
|
||||
|
||||
@@ -131,67 +131,139 @@ public static class QBEGenerator
|
||||
return $"$impl{++_implFuncNameIndex}";
|
||||
}
|
||||
|
||||
private static string StructTypeName(BoundNubStructType structType)
|
||||
private static string CustomTypeName(NubCustomType customType)
|
||||
{
|
||||
return $":{structType.Namespace}_{structType.Name}";
|
||||
return CustomTypeName(customType.Namespace, customType.Name);
|
||||
}
|
||||
|
||||
private static string TraitTypeName(BoundNubTraitType traitType)
|
||||
private static string CustomTypeName(string @namespace, string name)
|
||||
{
|
||||
return $":{traitType.Namespace}_{traitType.Name}";
|
||||
return $":{@namespace}_{name}";
|
||||
}
|
||||
|
||||
private static void EmitStore(BoundNubType type, string value, string destination)
|
||||
private static int AlignTo(int offset, int alignment)
|
||||
{
|
||||
var store = type switch
|
||||
return (offset + alignment - 1) & ~(alignment - 1);
|
||||
}
|
||||
|
||||
private static int SizeOf(NubType type)
|
||||
{
|
||||
if (type.IsSimpleType(out var simpleType, out var complexType))
|
||||
{
|
||||
BoundNubComplexType => "storel",
|
||||
BoundNubSimpleType simpleType => simpleType switch
|
||||
return simpleType.StorageSize switch
|
||||
{
|
||||
BoundNubFuncType or BoundNubPointerType => "loadl",
|
||||
BoundNubPrimitiveType primitiveType => primitiveType.Kind switch
|
||||
StorageSize.I64 or StorageSize.U64 or StorageSize.F64 => 8,
|
||||
StorageSize.I32 or StorageSize.U32 or StorageSize.F32 => 4,
|
||||
StorageSize.I16 or StorageSize.U16 => 2,
|
||||
StorageSize.I8 or StorageSize.U8 => 1,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(simpleType.StorageSize))
|
||||
};
|
||||
}
|
||||
|
||||
// Only custom types such as structs/traits have known sizes for now. For objects other than custom types, we store pointers
|
||||
if (complexType is not NubCustomType customType)
|
||||
{
|
||||
return 8;
|
||||
}
|
||||
|
||||
switch (customType.Kind(_definitionTable))
|
||||
{
|
||||
case CustomTypeKind.Struct:
|
||||
{
|
||||
var structDef = _definitionTable.LookupStruct(customType.Namespace, customType.Name);
|
||||
var size = 0;
|
||||
var maxAlignment = 1;
|
||||
|
||||
foreach (var field in structDef.Fields)
|
||||
{
|
||||
PrimitiveTypeKind.I64 or PrimitiveTypeKind.U64 => "storel",
|
||||
PrimitiveTypeKind.I32 or PrimitiveTypeKind.U32 => "storew",
|
||||
PrimitiveTypeKind.I16 or PrimitiveTypeKind.U16 => "storeh",
|
||||
PrimitiveTypeKind.I8 or PrimitiveTypeKind.U8 or PrimitiveTypeKind.Bool => "storeb",
|
||||
PrimitiveTypeKind.F64 => "stored",
|
||||
PrimitiveTypeKind.F32 => "stores",
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
},
|
||||
_ => throw new ArgumentOutOfRangeException($"'{type}' type cannot be used in store instructions")
|
||||
},
|
||||
_ => throw new UnreachableException()
|
||||
};
|
||||
var fieldAlignment = field.Type.Alignment(_definitionTable);
|
||||
maxAlignment = Math.Max(maxAlignment, fieldAlignment);
|
||||
|
||||
size = AlignTo(size, fieldAlignment);
|
||||
size += SizeOf(field.Type);
|
||||
}
|
||||
|
||||
return AlignTo(size, maxAlignment);
|
||||
}
|
||||
case CustomTypeKind.Trait:
|
||||
{
|
||||
return 16;
|
||||
}
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
private static int OffsetOf(BoundStructNode structDefinition, string member)
|
||||
{
|
||||
var offset = 0;
|
||||
|
||||
foreach (var field in structDefinition.Fields)
|
||||
{
|
||||
if (field.Name == member)
|
||||
{
|
||||
return offset;
|
||||
}
|
||||
|
||||
var fieldAlignment = field.Type.Alignment(_definitionTable);
|
||||
|
||||
offset = AlignTo(offset, fieldAlignment);
|
||||
offset += SizeOf(field.Type);
|
||||
}
|
||||
|
||||
throw new UnreachableException($"Member '{member}' not found in struct");
|
||||
}
|
||||
|
||||
private static void EmitStore(NubType type, string value, string destination)
|
||||
{
|
||||
string store;
|
||||
|
||||
if (type.IsSimpleType(out var simpleType, out _))
|
||||
{
|
||||
store = simpleType.StorageSize switch
|
||||
{
|
||||
StorageSize.I8 or StorageSize.U8 => "storeb",
|
||||
StorageSize.I16 or StorageSize.U16 => "storeh",
|
||||
StorageSize.I32 or StorageSize.U32 => "storew",
|
||||
StorageSize.I64 or StorageSize.U64 => "storel",
|
||||
StorageSize.F32 => "stores",
|
||||
StorageSize.F64 => "stored",
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(simpleType.StorageSize))
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
store = "storel";
|
||||
}
|
||||
|
||||
_writer.Indented($"{store} {value}, {destination}");
|
||||
}
|
||||
|
||||
private static Val EmitLoad(BoundNubType type, string from)
|
||||
private static Val EmitLoad(NubType type, string from)
|
||||
{
|
||||
var into = TmpName();
|
||||
var load = type switch
|
||||
string load;
|
||||
|
||||
if (type.IsSimpleType(out var simpleType, out _))
|
||||
{
|
||||
BoundNubComplexType => "loadl",
|
||||
BoundNubSimpleType simpleType => simpleType switch
|
||||
load = simpleType.StorageSize switch
|
||||
{
|
||||
BoundNubFuncType or BoundNubPointerType => "loadl",
|
||||
BoundNubPrimitiveType primitiveType => primitiveType.Kind switch
|
||||
{
|
||||
PrimitiveTypeKind.I64 or PrimitiveTypeKind.U64 => "loadl",
|
||||
PrimitiveTypeKind.I32 or PrimitiveTypeKind.U32 => "loadw",
|
||||
PrimitiveTypeKind.I16 => "loadsh",
|
||||
PrimitiveTypeKind.I8 => "loadsb",
|
||||
PrimitiveTypeKind.U16 => "loaduh",
|
||||
PrimitiveTypeKind.U8 or PrimitiveTypeKind.Bool => "loadub",
|
||||
PrimitiveTypeKind.F64 => "loadd",
|
||||
PrimitiveTypeKind.F32 => "loads",
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
},
|
||||
_ => throw new ArgumentOutOfRangeException($"'{type}' type cannot be used in load instructions")
|
||||
},
|
||||
_ => throw new UnreachableException()
|
||||
};
|
||||
StorageSize.I64 or StorageSize.U64 => "loadl",
|
||||
StorageSize.I32 or StorageSize.U32 => "loadw",
|
||||
StorageSize.I16 => "loadsh",
|
||||
StorageSize.I8 => "loadsb",
|
||||
StorageSize.U16 => "loaduh",
|
||||
StorageSize.U8 => "loadub",
|
||||
StorageSize.F64 => "loadd",
|
||||
StorageSize.F32 => "loads",
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(simpleType.StorageSize))
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
load = "loadl";
|
||||
}
|
||||
|
||||
var into = TmpName();
|
||||
|
||||
_writer.Indented($"{into} {QBEAssign(type)} {load} {from}");
|
||||
|
||||
@@ -203,7 +275,7 @@ public static class QBEGenerator
|
||||
_writer.Indented($"call $nub_memcpy(l {source}, l {destination}, l {length})");
|
||||
}
|
||||
|
||||
private static string EmitArraySizeInBytes(BoundNubArrayType type, string array)
|
||||
private static string EmitArraySizeInBytes(NubArrayType type, string array)
|
||||
{
|
||||
var size = TmpName();
|
||||
_writer.Indented($"{size} =l loadl {array}");
|
||||
@@ -265,52 +337,30 @@ public static class QBEGenerator
|
||||
|
||||
var value = EmitUnwrap(EmitExpression(source));
|
||||
|
||||
switch (source.Type)
|
||||
if (source.Type.IsSimpleType(out var simpleType, out var complexType))
|
||||
{
|
||||
case BoundNubComplexType complexType:
|
||||
EmitStore(simpleType, value, destinationPointer);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (complexType is NubCustomType customType)
|
||||
{
|
||||
EmitMemcpy(value, destinationPointer, SizeOf(customType).ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
var size = complexType switch
|
||||
{
|
||||
BoundNubArrayType arrayType => EmitArraySizeInBytes(arrayType, value),
|
||||
BoundNubCStringType => EmitCStringSizeInBytes(value),
|
||||
BoundNubStringType => EmitStringSizeInBytes(value),
|
||||
BoundNubStructType structType => SizeOf(structType).ToString(),
|
||||
BoundNubTraitType traitType => SizeOf(traitType).ToString(),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(complexType))
|
||||
NubArrayType arrayType => EmitArraySizeInBytes(arrayType, value),
|
||||
NubCStringType => EmitCStringSizeInBytes(value),
|
||||
NubStringType => EmitStringSizeInBytes(value),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(source.Type))
|
||||
};
|
||||
|
||||
switch (complexType)
|
||||
{
|
||||
case BoundNubArrayType:
|
||||
case BoundNubCStringType:
|
||||
case BoundNubStringType:
|
||||
{
|
||||
var buffer = TmpName();
|
||||
_writer.Indented($"{buffer} =l alloc8 {size}");
|
||||
EmitMemcpy(value, buffer, size);
|
||||
EmitStore(source.Type, buffer, destinationPointer);
|
||||
return;
|
||||
}
|
||||
case BoundNubStructType:
|
||||
case BoundNubTraitType:
|
||||
{
|
||||
EmitMemcpy(value, destinationPointer, size);
|
||||
return;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(complexType));
|
||||
}
|
||||
}
|
||||
}
|
||||
case BoundNubSimpleType simpleType:
|
||||
{
|
||||
EmitStore(simpleType, value, destinationPointer);
|
||||
return;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(source.Type));
|
||||
var buffer = TmpName();
|
||||
_writer.Indented($"{buffer} =l alloc8 {size}");
|
||||
EmitMemcpy(value, buffer, size);
|
||||
EmitStore(complexType, buffer, destinationPointer);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -342,46 +392,36 @@ public static class QBEGenerator
|
||||
|
||||
var value = EmitUnwrap(EmitExpression(source));
|
||||
|
||||
switch (source.Type)
|
||||
if (source.Type.IsSimpleType(out _, out var complexType))
|
||||
{
|
||||
case BoundNubComplexType complexType:
|
||||
{
|
||||
var destination = TmpName();
|
||||
|
||||
var size = complexType switch
|
||||
{
|
||||
BoundNubArrayType arrayType => EmitArraySizeInBytes(arrayType, value),
|
||||
BoundNubCStringType => EmitCStringSizeInBytes(value),
|
||||
BoundNubStringType => EmitStringSizeInBytes(value),
|
||||
BoundNubStructType structType => SizeOf(structType).ToString(),
|
||||
BoundNubTraitType traitType => SizeOf(traitType).ToString(),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(complexType))
|
||||
};
|
||||
|
||||
_writer.Indented($"{destination} =l alloc8 {size}");
|
||||
EmitMemcpy(value, destination, size);
|
||||
return destination;
|
||||
}
|
||||
case BoundNubSimpleType:
|
||||
{
|
||||
return value;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(source.Type));
|
||||
}
|
||||
// Simple types are passed in registers and are therefore always copied
|
||||
return value;
|
||||
}
|
||||
|
||||
var size = complexType switch
|
||||
{
|
||||
NubArrayType arrayType => EmitArraySizeInBytes(arrayType, value),
|
||||
NubCStringType => EmitCStringSizeInBytes(value),
|
||||
NubStringType => EmitStringSizeInBytes(value),
|
||||
NubCustomType customType => SizeOf(customType).ToString(),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(source.Type))
|
||||
};
|
||||
|
||||
var destination = TmpName();
|
||||
_writer.Indented($"{destination} =l alloc8 {size}");
|
||||
EmitMemcpy(value, destination, size);
|
||||
return destination;
|
||||
}
|
||||
|
||||
private static string QBEAssign(BoundNubType type)
|
||||
private static string QBEAssign(NubType type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
BoundNubComplexType => "=l",
|
||||
BoundNubSimpleType simpleType => simpleType switch
|
||||
NubComplexType => "=l",
|
||||
NubSimpleType simpleType => simpleType switch
|
||||
{
|
||||
BoundNubFuncType or BoundNubFuncType => "=l",
|
||||
BoundNubPrimitiveType primitiveType => primitiveType.Kind switch
|
||||
NubFuncType or NubFuncType => "=l",
|
||||
NubPrimitiveType primitiveType => primitiveType.Kind switch
|
||||
{
|
||||
PrimitiveTypeKind.I64 or PrimitiveTypeKind.U64 => "=l",
|
||||
PrimitiveTypeKind.I32 or PrimitiveTypeKind.U32 => "=w",
|
||||
@@ -397,139 +437,34 @@ public static class QBEGenerator
|
||||
};
|
||||
}
|
||||
|
||||
private static int AlignmentOf(BoundNubType type)
|
||||
// Utility to create QBE type names for function parameters and return types
|
||||
private static string FuncQBETypeName(NubType type)
|
||||
{
|
||||
switch (type)
|
||||
if (type.IsSimpleType(out var simpleType, out var complexType))
|
||||
{
|
||||
case BoundNubPrimitiveType primitiveType:
|
||||
return simpleType.StorageSize switch
|
||||
{
|
||||
return primitiveType.Kind switch
|
||||
{
|
||||
PrimitiveTypeKind.I64 or PrimitiveTypeKind.U64 or PrimitiveTypeKind.F64 => 8,
|
||||
PrimitiveTypeKind.I32 or PrimitiveTypeKind.U32 or PrimitiveTypeKind.F32 => 4,
|
||||
PrimitiveTypeKind.I16 or PrimitiveTypeKind.U16 => 2,
|
||||
PrimitiveTypeKind.I8 or PrimitiveTypeKind.U8 or PrimitiveTypeKind.Bool => 1,
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
};
|
||||
}
|
||||
case BoundNubStructType structType:
|
||||
{
|
||||
var structDef = _definitionTable.LookupStruct(structType.Namespace, structType.Name);
|
||||
return structDef.Fields.Max(f => AlignmentOf(f.Type));
|
||||
}
|
||||
case BoundNubTraitType:
|
||||
case BoundNubPointerType:
|
||||
case BoundNubArrayType:
|
||||
case BoundNubCStringType:
|
||||
case BoundNubStringType:
|
||||
case BoundNubFuncType:
|
||||
return 8;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
private static int AlignTo(int offset, int alignment)
|
||||
{
|
||||
return (offset + alignment - 1) & ~(alignment - 1);
|
||||
}
|
||||
|
||||
private static int SizeOf(BoundNubType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case BoundNubPrimitiveType primitiveType:
|
||||
{
|
||||
return primitiveType.Kind switch
|
||||
{
|
||||
PrimitiveTypeKind.I64 or PrimitiveTypeKind.U64 or PrimitiveTypeKind.F64 => 8,
|
||||
PrimitiveTypeKind.I32 or PrimitiveTypeKind.U32 or PrimitiveTypeKind.F32 => 4,
|
||||
PrimitiveTypeKind.I16 or PrimitiveTypeKind.U16 => 2,
|
||||
PrimitiveTypeKind.I8 or PrimitiveTypeKind.U8 or PrimitiveTypeKind.Bool => 1,
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
};
|
||||
}
|
||||
case BoundNubStructType structType:
|
||||
{
|
||||
var structDef = _definitionTable.LookupStruct(structType.Namespace, structType.Name);
|
||||
var size = 0;
|
||||
var maxAlignment = 1;
|
||||
|
||||
foreach (var field in structDef.Fields)
|
||||
{
|
||||
var fieldAlignment = AlignmentOf(field.Type);
|
||||
maxAlignment = Math.Max(maxAlignment, fieldAlignment);
|
||||
|
||||
size = AlignTo(size, fieldAlignment);
|
||||
size += SizeOf(field.Type);
|
||||
}
|
||||
|
||||
size = AlignTo(size, maxAlignment);
|
||||
|
||||
return size;
|
||||
}
|
||||
case BoundNubTraitType:
|
||||
return 16;
|
||||
case BoundNubPointerType:
|
||||
case BoundNubArrayType:
|
||||
case BoundNubCStringType:
|
||||
case BoundNubStringType:
|
||||
case BoundNubFuncType:
|
||||
return 8;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
private static int OffsetOf(BoundStructNode structDefinition, string member)
|
||||
{
|
||||
var offset = 0;
|
||||
|
||||
foreach (var field in structDefinition.Fields)
|
||||
{
|
||||
if (field.Name == member)
|
||||
{
|
||||
return offset;
|
||||
}
|
||||
|
||||
var fieldAlignment = AlignmentOf(field.Type);
|
||||
|
||||
offset = AlignTo(offset, fieldAlignment);
|
||||
offset += SizeOf(field.Type);
|
||||
StorageSize.I64 or StorageSize.U64 => "l",
|
||||
StorageSize.I32 or StorageSize.U32 => "w",
|
||||
StorageSize.I16 => "sh",
|
||||
StorageSize.I8 => "sb",
|
||||
StorageSize.U16 => "uh",
|
||||
StorageSize.U8 => "ub",
|
||||
StorageSize.F64 => "d",
|
||||
StorageSize.F32 => "s",
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
};
|
||||
}
|
||||
|
||||
throw new UnreachableException($"Member '{member}' not found in struct");
|
||||
}
|
||||
|
||||
private static string FuncQBETypeName(BoundNubType type)
|
||||
{
|
||||
return type switch
|
||||
if (complexType is NubCustomType customType)
|
||||
{
|
||||
BoundNubStructType structType => StructTypeName(structType),
|
||||
BoundNubTraitType traitType => TraitTypeName(traitType),
|
||||
BoundNubComplexType => "l",
|
||||
BoundNubSimpleType simpleType => simpleType switch
|
||||
{
|
||||
BoundNubPointerType or BoundNubFuncType => "l",
|
||||
BoundNubPrimitiveType primitiveType => primitiveType.Kind switch
|
||||
{
|
||||
PrimitiveTypeKind.I64 or PrimitiveTypeKind.U64 => "l",
|
||||
PrimitiveTypeKind.I32 or PrimitiveTypeKind.U32 => "w",
|
||||
PrimitiveTypeKind.I16 => "sh",
|
||||
PrimitiveTypeKind.I8 => "sb",
|
||||
PrimitiveTypeKind.U16 => "uh",
|
||||
PrimitiveTypeKind.U8 or PrimitiveTypeKind.Bool => "ub",
|
||||
PrimitiveTypeKind.F64 => "d",
|
||||
PrimitiveTypeKind.F32 => "s",
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
},
|
||||
_ => throw new NotSupportedException($"'{type}' type cannot be used as a function definition type")
|
||||
},
|
||||
_ => throw new UnreachableException()
|
||||
};
|
||||
return CustomTypeName(customType);
|
||||
}
|
||||
|
||||
return "l";
|
||||
}
|
||||
|
||||
private static void EmitFuncDefinition(BoundNode debugNode, string name, List<BoundFuncParameterNode> parameters, BoundNubType returnType, BoundBlock body, bool exported)
|
||||
private static void EmitFuncDefinition(BoundNode debugNode, string name, List<BoundFuncParameterNode> parameters, NubType returnType, BoundBlock body, bool exported)
|
||||
{
|
||||
_variables.Clear();
|
||||
_variableScopes.Clear();
|
||||
@@ -544,7 +479,7 @@ public static class QBEGenerator
|
||||
}
|
||||
|
||||
builder.Append("function ");
|
||||
if (returnType is not BoundNubVoidType)
|
||||
if (returnType is not NubVoidType)
|
||||
{
|
||||
builder.Append(FuncQBETypeName(returnType) + ' ');
|
||||
}
|
||||
@@ -564,7 +499,7 @@ public static class QBEGenerator
|
||||
|
||||
if (body.Statements.LastOrDefault() is not BoundReturnNode)
|
||||
{
|
||||
if (returnType is BoundNubVoidType)
|
||||
if (returnType is NubVoidType)
|
||||
{
|
||||
_writer.Indented("ret");
|
||||
}
|
||||
@@ -575,7 +510,7 @@ public static class QBEGenerator
|
||||
|
||||
private static void EmitStructDefinition(BoundStructNode structDef)
|
||||
{
|
||||
_writer.WriteLine($"type {StructTypeName(new BoundNubStructType(structDef.Namespace, structDef.Name))} = {{ ");
|
||||
_writer.WriteLine($"type {CustomTypeName(structDef.Namespace, structDef.Name)} = {{ ");
|
||||
|
||||
var types = new Dictionary<string, string>();
|
||||
|
||||
@@ -596,34 +531,32 @@ public static class QBEGenerator
|
||||
|
||||
string StructDefQBEType(BoundStructFieldNode field)
|
||||
{
|
||||
return field.Type switch
|
||||
if (field.Type.IsSimpleType(out var simpleType, out var complexType))
|
||||
{
|
||||
BoundNubStructType structType => StructTypeName(structType),
|
||||
BoundNubTraitType traitType => TraitTypeName(traitType),
|
||||
BoundNubComplexType => "l",
|
||||
BoundNubSimpleType simpleType => simpleType switch
|
||||
return simpleType.StorageSize switch
|
||||
{
|
||||
BoundNubPointerType or BoundNubFuncType => "l",
|
||||
BoundNubPrimitiveType primitiveType => primitiveType.Kind switch
|
||||
{
|
||||
PrimitiveTypeKind.I64 or PrimitiveTypeKind.U64 => "l",
|
||||
PrimitiveTypeKind.I32 or PrimitiveTypeKind.U32 => "w",
|
||||
PrimitiveTypeKind.I16 or PrimitiveTypeKind.U16 => "h",
|
||||
PrimitiveTypeKind.I8 or PrimitiveTypeKind.U8 or PrimitiveTypeKind.Bool => "b",
|
||||
PrimitiveTypeKind.F64 => "d",
|
||||
PrimitiveTypeKind.F32 => "s",
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
},
|
||||
_ => throw new NotSupportedException($"'{field.Type}' type cannot be used in structs")
|
||||
},
|
||||
_ => throw new UnreachableException()
|
||||
};
|
||||
StorageSize.I64 or StorageSize.U64 => "l",
|
||||
StorageSize.I32 or StorageSize.U32 => "w",
|
||||
StorageSize.I16 or StorageSize.U16 => "h",
|
||||
StorageSize.I8 or StorageSize.U8 => "b",
|
||||
StorageSize.F64 => "d",
|
||||
StorageSize.F32 => "s",
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
};
|
||||
}
|
||||
|
||||
if (complexType is NubCustomType customType)
|
||||
{
|
||||
return CustomTypeName(customType);
|
||||
}
|
||||
|
||||
return "l";
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmitTraitVTable(BoundTraitNode traitDef)
|
||||
{
|
||||
_writer.WriteLine($"type {TraitTypeName(new BoundNubTraitType(traitDef.Namespace, traitDef.Name))} = {{");
|
||||
_writer.WriteLine($"type {CustomTypeName(traitDef.Namespace, traitDef.Name)} = {{");
|
||||
|
||||
foreach (var func in traitDef.Functions)
|
||||
{
|
||||
@@ -643,10 +576,10 @@ public static class QBEGenerator
|
||||
EmitAssignment(assignment);
|
||||
break;
|
||||
case BoundBreakNode @break:
|
||||
EmitBreak(@break);
|
||||
EmitBreak();
|
||||
break;
|
||||
case BoundContinueNode @continue:
|
||||
EmitContinue(@continue);
|
||||
EmitContinue();
|
||||
break;
|
||||
case BoundIfNode ifStatement:
|
||||
EmitIf(ifStatement);
|
||||
@@ -700,13 +633,13 @@ public static class QBEGenerator
|
||||
_codeIsReachable = true;
|
||||
}
|
||||
|
||||
private static void EmitBreak(BoundBreakNode @break)
|
||||
private static void EmitBreak()
|
||||
{
|
||||
_writer.Indented($"jmp {_breakLabels.Peek()}");
|
||||
_codeIsReachable = false;
|
||||
}
|
||||
|
||||
private static void EmitContinue(BoundContinueNode @continue)
|
||||
private static void EmitContinue()
|
||||
{
|
||||
_writer.Indented($"jmp {_continueLabels.Peek()}");
|
||||
_codeIsReachable = false;
|
||||
@@ -821,7 +754,7 @@ public static class QBEGenerator
|
||||
var array = EmitUnwrap(EmitExpression(arrayIndexAccess.Target));
|
||||
var index = EmitUnwrap(EmitExpression(arrayIndexAccess.Index));
|
||||
|
||||
var elementType = ((BoundNubArrayType)arrayIndexAccess.Target.Type).ElementType;
|
||||
var elementType = ((NubArrayType)arrayIndexAccess.Target.Type).ElementType;
|
||||
|
||||
var pointer = TmpName();
|
||||
_writer.Indented($"{pointer} =l mul {index}, {SizeOf(elementType)}");
|
||||
@@ -900,7 +833,7 @@ public static class QBEGenerator
|
||||
return new Val(outputName, binaryExpression.Type, ValKind.Direct);
|
||||
}
|
||||
|
||||
private static string EmitBinaryInstructionFor(BinaryExpressionOperator op, BoundNubType type, string left, string right)
|
||||
private static string EmitBinaryInstructionFor(BinaryExpressionOperator op, NubType type, string left, string right)
|
||||
{
|
||||
if (op is
|
||||
BinaryExpressionOperator.Equal or
|
||||
@@ -912,47 +845,41 @@ public static class QBEGenerator
|
||||
{
|
||||
char suffix;
|
||||
|
||||
if (type.Is8BitInteger)
|
||||
if (!type.IsSimpleType(out var simpleType, out _))
|
||||
{
|
||||
if (type.IsSignedInteger)
|
||||
{
|
||||
throw new NotSupportedException("Binary operations is only supported for simple types.");
|
||||
}
|
||||
|
||||
switch (simpleType.StorageSize)
|
||||
{
|
||||
case StorageSize.I8:
|
||||
_writer.Indented($"{left} =w extsb {left}");
|
||||
_writer.Indented($"{right} =w extsb {right}");
|
||||
}
|
||||
else
|
||||
{
|
||||
suffix = 'w';
|
||||
break;
|
||||
case StorageSize.U8:
|
||||
_writer.Indented($"{left} =w extub {left}");
|
||||
_writer.Indented($"{right} =w extub {right}");
|
||||
}
|
||||
|
||||
suffix = 'w';
|
||||
}
|
||||
else if (type.Is16BitInteger)
|
||||
{
|
||||
if (type.IsSignedInteger)
|
||||
{
|
||||
suffix = 'w';
|
||||
break;
|
||||
case StorageSize.I16:
|
||||
_writer.Indented($"{left} =w extsh {left}");
|
||||
_writer.Indented($"{right} =w extsh {right}");
|
||||
}
|
||||
else
|
||||
{
|
||||
suffix = 'w';
|
||||
break;
|
||||
case StorageSize.U16:
|
||||
_writer.Indented($"{left} =w extuh {left}");
|
||||
_writer.Indented($"{right} =w extuh {right}");
|
||||
}
|
||||
|
||||
suffix = 'w';
|
||||
}
|
||||
else if (type.Is32BitInteger)
|
||||
{
|
||||
suffix = 'w';
|
||||
}
|
||||
else if (type.Is64BitInteger)
|
||||
{
|
||||
suffix = 'l';
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotSupportedException($"Unsupported type '{type}' for binary operator '{op}'");
|
||||
suffix = 'w';
|
||||
break;
|
||||
case StorageSize.I32 or StorageSize.U32:
|
||||
suffix = 'w';
|
||||
break;
|
||||
case StorageSize.I64 or StorageSize.U64:
|
||||
suffix = 'l';
|
||||
break;
|
||||
default:
|
||||
throw new NotSupportedException($"Unsupported type '{simpleType}' for binary operator '{op}'");
|
||||
}
|
||||
|
||||
if (op is BinaryExpressionOperator.Equal)
|
||||
@@ -967,18 +894,14 @@ public static class QBEGenerator
|
||||
|
||||
string sign;
|
||||
|
||||
if (type.IsSignedInteger)
|
||||
if (simpleType is NubPrimitiveType { Kind: PrimitiveTypeKind.I8 or PrimitiveTypeKind.I16 or PrimitiveTypeKind.I32 or PrimitiveTypeKind.I64 })
|
||||
{
|
||||
sign = "s";
|
||||
}
|
||||
else if (type.IsUnsignedInteger)
|
||||
else if (simpleType is NubPrimitiveType { Kind: PrimitiveTypeKind.U8 or PrimitiveTypeKind.U16 or PrimitiveTypeKind.U32 or PrimitiveTypeKind.U64 })
|
||||
{
|
||||
sign = "u";
|
||||
}
|
||||
else if (type.IsFloat)
|
||||
{
|
||||
sign = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotSupportedException($"Unsupported type '{type}' for binary operator '{op}'");
|
||||
@@ -1027,21 +950,21 @@ public static class QBEGenerator
|
||||
{
|
||||
case LiteralKind.Integer:
|
||||
{
|
||||
if (literal.Type.IsFloat32)
|
||||
if (literal.Type is NubPrimitiveType { Kind: PrimitiveTypeKind.F32 })
|
||||
{
|
||||
var value = float.Parse(literal.Literal, CultureInfo.InvariantCulture);
|
||||
var bits = BitConverter.SingleToInt32Bits(value);
|
||||
return new Val(bits.ToString(), literal.Type, ValKind.Direct);
|
||||
}
|
||||
|
||||
if (literal.Type.IsFloat64)
|
||||
if (literal.Type is NubPrimitiveType { Kind: PrimitiveTypeKind.F64 })
|
||||
{
|
||||
var value = double.Parse(literal.Literal, CultureInfo.InvariantCulture);
|
||||
var bits = BitConverter.DoubleToInt64Bits(value);
|
||||
return new Val(bits.ToString(), literal.Type, ValKind.Direct);
|
||||
}
|
||||
|
||||
if (literal.Type.IsInteger)
|
||||
if (literal.Type is NubPrimitiveType { Kind: PrimitiveTypeKind.I8 or PrimitiveTypeKind.U8 or PrimitiveTypeKind.I16 or PrimitiveTypeKind.U16 or PrimitiveTypeKind.I32 or PrimitiveTypeKind.U32 or PrimitiveTypeKind.I64 or PrimitiveTypeKind.U64 })
|
||||
{
|
||||
return new Val(literal.Literal, literal.Type, ValKind.Direct);
|
||||
}
|
||||
@@ -1050,19 +973,19 @@ public static class QBEGenerator
|
||||
}
|
||||
case LiteralKind.Float:
|
||||
{
|
||||
if (literal.Type.IsInteger)
|
||||
if (literal.Type is NubPrimitiveType { Kind: PrimitiveTypeKind.I8 or PrimitiveTypeKind.U8 or PrimitiveTypeKind.I16 or PrimitiveTypeKind.U16 or PrimitiveTypeKind.I32 or PrimitiveTypeKind.U32 or PrimitiveTypeKind.I64 or PrimitiveTypeKind.U64 })
|
||||
{
|
||||
return new Val(literal.Literal.Split(".").First(), literal.Type, ValKind.Direct);
|
||||
}
|
||||
|
||||
if (literal.Type.IsFloat32)
|
||||
if (literal.Type is NubPrimitiveType { Kind: PrimitiveTypeKind.F32 })
|
||||
{
|
||||
var value = float.Parse(literal.Literal, CultureInfo.InvariantCulture);
|
||||
var bits = BitConverter.SingleToInt32Bits(value);
|
||||
return new Val(bits.ToString(), literal.Type, ValKind.Direct);
|
||||
}
|
||||
|
||||
if (literal.Type.IsFloat64)
|
||||
if (literal.Type is NubPrimitiveType { Kind: PrimitiveTypeKind.F64 })
|
||||
{
|
||||
var value = double.Parse(literal.Literal, CultureInfo.InvariantCulture);
|
||||
var bits = BitConverter.DoubleToInt64Bits(value);
|
||||
@@ -1073,14 +996,14 @@ public static class QBEGenerator
|
||||
}
|
||||
case LiteralKind.String:
|
||||
{
|
||||
if (literal.Type.IsString)
|
||||
if (literal.Type is NubStringType)
|
||||
{
|
||||
var stringLiteral = new StringLiteral(literal.Literal, StringName());
|
||||
_stringLiterals.Add(stringLiteral);
|
||||
return new Val(stringLiteral.Name, literal.Type, ValKind.Direct);
|
||||
}
|
||||
|
||||
if (literal.Type.IsCString)
|
||||
if (literal.Type is NubCStringType)
|
||||
{
|
||||
var cStringLiteral = new CStringLiteral(literal.Literal, CStringName());
|
||||
_cStringLiterals.Add(cStringLiteral);
|
||||
@@ -1091,7 +1014,7 @@ public static class QBEGenerator
|
||||
}
|
||||
case LiteralKind.Bool:
|
||||
{
|
||||
if (literal.Type.IsBool)
|
||||
if (literal.Type is NubPrimitiveType { Kind: PrimitiveTypeKind.Bool })
|
||||
{
|
||||
return new Val(bool.Parse(literal.Literal) ? "1" : "0", literal.Type, ValKind.Direct);
|
||||
}
|
||||
@@ -1142,16 +1065,16 @@ public static class QBEGenerator
|
||||
{
|
||||
switch (unaryExpression.Operand.Type)
|
||||
{
|
||||
case BoundNubPrimitiveType { Kind: PrimitiveTypeKind.I64 }:
|
||||
case NubPrimitiveType { Kind: PrimitiveTypeKind.I64 }:
|
||||
_writer.Indented($"{outputName} =l neg {operand}");
|
||||
return new Val(outputName, unaryExpression.Type, ValKind.Direct);
|
||||
case BoundNubPrimitiveType { Kind: PrimitiveTypeKind.I32 or PrimitiveTypeKind.I16 or PrimitiveTypeKind.I8 }:
|
||||
case NubPrimitiveType { Kind: PrimitiveTypeKind.I32 or PrimitiveTypeKind.I16 or PrimitiveTypeKind.I8 }:
|
||||
_writer.Indented($"{outputName} =w neg {operand}");
|
||||
return new Val(outputName, unaryExpression.Type, ValKind.Direct);
|
||||
case BoundNubPrimitiveType { Kind: PrimitiveTypeKind.F64 }:
|
||||
case NubPrimitiveType { Kind: PrimitiveTypeKind.F64 }:
|
||||
_writer.Indented($"{outputName} =d neg {operand}");
|
||||
return new Val(outputName, unaryExpression.Type, ValKind.Direct);
|
||||
case BoundNubPrimitiveType { Kind: PrimitiveTypeKind.F32 }:
|
||||
case NubPrimitiveType { Kind: PrimitiveTypeKind.F32 }:
|
||||
_writer.Indented($"{outputName} =s neg {operand}");
|
||||
return new Val(outputName, unaryExpression.Type, ValKind.Direct);
|
||||
}
|
||||
@@ -1162,7 +1085,7 @@ public static class QBEGenerator
|
||||
{
|
||||
switch (unaryExpression.Operand.Type)
|
||||
{
|
||||
case BoundNubPrimitiveType { Kind: PrimitiveTypeKind.Bool }:
|
||||
case NubPrimitiveType { Kind: PrimitiveTypeKind.Bool }:
|
||||
_writer.Indented($"{outputName} =w xor {operand}, 1");
|
||||
return new Val(outputName, unaryExpression.Type, ValKind.Direct);
|
||||
}
|
||||
@@ -1189,7 +1112,7 @@ public static class QBEGenerator
|
||||
_writer.Indented($"{output} =l add {target}, {offset}");
|
||||
|
||||
// If the accessed member is an inline struct, it will not be a pointer
|
||||
if (structFieldAccess.Type is BoundNubStructType)
|
||||
if (structFieldAccess.Type is NubCustomType customType && customType.Kind(_definitionTable) == CustomTypeKind.Struct)
|
||||
{
|
||||
return new Val(output, structFieldAccess.Type, ValKind.Direct);
|
||||
}
|
||||
@@ -1232,7 +1155,7 @@ public static class QBEGenerator
|
||||
parameterStrings.Add($"{FuncQBETypeName(parameter.Type)} {copy}");
|
||||
}
|
||||
|
||||
if (funcCall.Type.IsVoid)
|
||||
if (funcCall.Type is NubVoidType)
|
||||
{
|
||||
_writer.Indented($"call {funcPointer}({string.Join(", ", parameterStrings)})");
|
||||
return new Val(string.Empty, funcCall.Type, ValKind.Direct);
|
||||
@@ -1274,7 +1197,7 @@ internal class Variable(string name, Val val)
|
||||
public Val Val { get; } = val;
|
||||
}
|
||||
|
||||
internal record Val(string Name, BoundNubType Type, ValKind Kind, MethodCallContext? FuncCallContext = null);
|
||||
internal record Val(string Name, NubType Type, ValKind Kind, MethodCallContext? FuncCallContext = null);
|
||||
|
||||
internal record MethodCallContext(Val ThisArg);
|
||||
|
||||
|
||||
@@ -1,191 +0,0 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace NubLang;
|
||||
|
||||
public abstract class BoundNubType : IEquatable<BoundNubType>
|
||||
{
|
||||
public bool Is8BitInteger => this is BoundNubPrimitiveType { Kind: PrimitiveTypeKind.I8 or PrimitiveTypeKind.U8 };
|
||||
public bool Is16BitInteger => this is BoundNubPrimitiveType { Kind: PrimitiveTypeKind.I16 or PrimitiveTypeKind.U16 };
|
||||
public bool Is32BitInteger => this is BoundNubPrimitiveType { Kind: PrimitiveTypeKind.I32 or PrimitiveTypeKind.U32 };
|
||||
public bool Is64BitInteger => this is BoundNubPrimitiveType { Kind: PrimitiveTypeKind.I64 or PrimitiveTypeKind.U64 };
|
||||
|
||||
public bool IsSignedInteger => this is BoundNubPrimitiveType { Kind: PrimitiveTypeKind.I8 or PrimitiveTypeKind.I16 or PrimitiveTypeKind.I32 or PrimitiveTypeKind.I64 };
|
||||
public bool IsUnsignedInteger => this is BoundNubPrimitiveType { Kind: PrimitiveTypeKind.U8 or PrimitiveTypeKind.U16 or PrimitiveTypeKind.U32 or PrimitiveTypeKind.U64 };
|
||||
public bool IsInteger => IsSignedInteger || IsUnsignedInteger;
|
||||
|
||||
public bool IsFloat32 => this is BoundNubPrimitiveType { Kind: PrimitiveTypeKind.F32 };
|
||||
public bool IsFloat64 => this is BoundNubPrimitiveType { Kind: PrimitiveTypeKind.F64 };
|
||||
public bool IsFloat => IsFloat32 || IsFloat64;
|
||||
|
||||
public bool IsNumber => IsFloat || IsInteger;
|
||||
|
||||
public bool IsVoid => this is BoundNubVoidType;
|
||||
public bool IsString => this is BoundNubStringType;
|
||||
public bool IsCString => this is BoundNubCStringType;
|
||||
public bool IsBool => this is BoundNubPrimitiveType { Kind: PrimitiveTypeKind.Bool };
|
||||
|
||||
public override bool Equals(object? obj) => obj is BoundNubType other && Equals(other);
|
||||
|
||||
public abstract bool Equals(BoundNubType? other);
|
||||
public abstract override int GetHashCode();
|
||||
public abstract override string ToString();
|
||||
|
||||
public static bool operator ==(BoundNubType? left, BoundNubType? right) => Equals(left, right);
|
||||
public static bool operator !=(BoundNubType? left, BoundNubType? right) => !Equals(left, right);
|
||||
}
|
||||
|
||||
public abstract class BoundNubComplexType : BoundNubType;
|
||||
|
||||
public abstract class BoundNubSimpleType : BoundNubType;
|
||||
|
||||
public class BoundNubCStringType : BoundNubComplexType
|
||||
{
|
||||
public override string ToString() => "cstring";
|
||||
public override bool Equals(BoundNubType? other) => other is BoundNubCStringType;
|
||||
public override int GetHashCode() => HashCode.Combine(typeof(BoundNubCStringType));
|
||||
}
|
||||
|
||||
public class BoundNubStringType : BoundNubComplexType
|
||||
{
|
||||
public override string ToString() => "string";
|
||||
public override bool Equals(BoundNubType? other) => other is BoundNubStringType;
|
||||
public override int GetHashCode() => HashCode.Combine(typeof(BoundNubStringType));
|
||||
}
|
||||
|
||||
public class BoundNubFuncType(BoundNubType returnType, List<BoundNubType> parameters) : BoundNubSimpleType
|
||||
{
|
||||
public BoundNubType ReturnType { get; } = returnType;
|
||||
public List<BoundNubType> Parameters { get; } = parameters;
|
||||
|
||||
public override string ToString() => $"func({string.Join(", ", Parameters)}): {ReturnType}";
|
||||
|
||||
public override bool Equals(BoundNubType? other) => other is BoundNubFuncType func && ReturnType.Equals(func.ReturnType) && Parameters.SequenceEqual(func.Parameters);
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
var hash = new HashCode();
|
||||
hash.Add(typeof(BoundNubFuncType));
|
||||
hash.Add(ReturnType);
|
||||
foreach (var param in Parameters)
|
||||
{
|
||||
hash.Add(param);
|
||||
}
|
||||
|
||||
return hash.ToHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
public class BoundNubStructType(string @namespace, string name) : BoundNubComplexType
|
||||
{
|
||||
public string Namespace { get; } = @namespace;
|
||||
public string Name { get; } = name;
|
||||
|
||||
public override string ToString() => $"{Namespace}::{Name}";
|
||||
|
||||
public override bool Equals(BoundNubType? other) => other is BoundNubStructType custom && Namespace == custom.Namespace && Name == custom.Name;
|
||||
public override int GetHashCode() => HashCode.Combine(typeof(BoundNubStructType), Namespace, Name);
|
||||
}
|
||||
|
||||
public class BoundNubTraitType(string @namespace, string name) : BoundNubComplexType
|
||||
{
|
||||
public string Namespace { get; } = @namespace;
|
||||
public string Name { get; } = name;
|
||||
|
||||
public override string ToString() => $"{Namespace}::{Name}";
|
||||
|
||||
public override bool Equals(BoundNubType? other) => other is BoundNubTraitType custom && Namespace == custom.Namespace && Name == custom.Name;
|
||||
public override int GetHashCode() => HashCode.Combine(typeof(BoundNubTraitType), Namespace, Name);
|
||||
}
|
||||
|
||||
public class BoundNubPointerType(BoundNubType baseType) : BoundNubSimpleType
|
||||
{
|
||||
public BoundNubType BaseType { get; } = baseType;
|
||||
|
||||
public override string ToString() => "^" + BaseType;
|
||||
|
||||
public override bool Equals(BoundNubType? other) => other is BoundNubPointerType pointer && BaseType.Equals(pointer.BaseType);
|
||||
public override int GetHashCode() => HashCode.Combine(typeof(BoundNubPointerType), BaseType);
|
||||
}
|
||||
|
||||
public class BoundNubArrayType(BoundNubType elementType) : BoundNubComplexType
|
||||
{
|
||||
public BoundNubType ElementType { get; } = elementType;
|
||||
|
||||
public override string ToString() => "[]" + ElementType;
|
||||
|
||||
public override bool Equals(BoundNubType? other) => other is BoundNubArrayType array && ElementType.Equals(array.ElementType);
|
||||
public override int GetHashCode() => HashCode.Combine(typeof(BoundNubArrayType), ElementType);
|
||||
}
|
||||
|
||||
public class BoundNubVoidType : BoundNubSimpleType
|
||||
{
|
||||
public override string ToString() => "void";
|
||||
public override bool Equals(BoundNubType? other) => other is BoundNubVoidType;
|
||||
public override int GetHashCode() => HashCode.Combine(typeof(BoundNubVoidType));
|
||||
}
|
||||
|
||||
public class BoundNubPrimitiveType(PrimitiveTypeKind kind) : BoundNubSimpleType
|
||||
{
|
||||
public PrimitiveTypeKind Kind { get; } = kind;
|
||||
|
||||
public static BoundNubPrimitiveType I64 => new(PrimitiveTypeKind.I64);
|
||||
public static BoundNubPrimitiveType I32 => new(PrimitiveTypeKind.I32);
|
||||
public static BoundNubPrimitiveType I16 => new(PrimitiveTypeKind.I16);
|
||||
public static BoundNubPrimitiveType I8 => new(PrimitiveTypeKind.I8);
|
||||
|
||||
public static BoundNubPrimitiveType U64 => new(PrimitiveTypeKind.U64);
|
||||
public static BoundNubPrimitiveType U32 => new(PrimitiveTypeKind.U32);
|
||||
public static BoundNubPrimitiveType U16 => new(PrimitiveTypeKind.U16);
|
||||
public static BoundNubPrimitiveType U8 => new(PrimitiveTypeKind.U8);
|
||||
|
||||
public static BoundNubPrimitiveType F64 => new(PrimitiveTypeKind.F64);
|
||||
public static BoundNubPrimitiveType F32 => new(PrimitiveTypeKind.F32);
|
||||
|
||||
public static BoundNubPrimitiveType Bool => new(PrimitiveTypeKind.Bool);
|
||||
|
||||
public static bool TryParse(string s, [NotNullWhen(true)] out PrimitiveTypeKind? kind)
|
||||
{
|
||||
kind = s switch
|
||||
{
|
||||
"i64" => PrimitiveTypeKind.I64,
|
||||
"i32" => PrimitiveTypeKind.I32,
|
||||
"i16" => PrimitiveTypeKind.I16,
|
||||
"i8" => PrimitiveTypeKind.I8,
|
||||
"u64" => PrimitiveTypeKind.U64,
|
||||
"u32" => PrimitiveTypeKind.U32,
|
||||
"u16" => PrimitiveTypeKind.U16,
|
||||
"u8" => PrimitiveTypeKind.U8,
|
||||
"f64" => PrimitiveTypeKind.F64,
|
||||
"f32" => PrimitiveTypeKind.F32,
|
||||
"bool" => PrimitiveTypeKind.Bool,
|
||||
_ => null
|
||||
};
|
||||
|
||||
return kind != null;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Kind switch
|
||||
{
|
||||
PrimitiveTypeKind.I8 => "i8",
|
||||
PrimitiveTypeKind.I16 => "i16",
|
||||
PrimitiveTypeKind.I32 => "i32",
|
||||
PrimitiveTypeKind.I64 => "i64",
|
||||
|
||||
PrimitiveTypeKind.U8 => "u8",
|
||||
PrimitiveTypeKind.U16 => "u16",
|
||||
PrimitiveTypeKind.U32 => "u32",
|
||||
PrimitiveTypeKind.U64 => "u64",
|
||||
|
||||
PrimitiveTypeKind.F32 => "f32",
|
||||
PrimitiveTypeKind.F64 => "f64",
|
||||
|
||||
PrimitiveTypeKind.Bool => "bool",
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(kind), Kind, null)
|
||||
};
|
||||
}
|
||||
|
||||
public override bool Equals(BoundNubType? other) => other is BoundNubPrimitiveType primitive && primitive.Kind == Kind;
|
||||
public override int GetHashCode() => HashCode.Combine(typeof(BoundNubPrimitiveType), Kind.GetHashCode());
|
||||
}
|
||||
@@ -1,7 +1,44 @@
|
||||
namespace NubLang;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace NubLang;
|
||||
|
||||
public abstract class NubType : IEquatable<NubType>
|
||||
{
|
||||
public bool IsNumber => this is NubPrimitiveType
|
||||
{
|
||||
Kind: PrimitiveTypeKind.I8
|
||||
or PrimitiveTypeKind.I16
|
||||
or PrimitiveTypeKind.I32
|
||||
or PrimitiveTypeKind.I64
|
||||
or PrimitiveTypeKind.U8
|
||||
or PrimitiveTypeKind.U16
|
||||
or PrimitiveTypeKind.U32
|
||||
or PrimitiveTypeKind.U64
|
||||
or PrimitiveTypeKind.F32
|
||||
or PrimitiveTypeKind.F64
|
||||
};
|
||||
|
||||
public bool IsSimpleType([NotNullWhen(true)] out NubSimpleType? simpleType, [NotNullWhen(false)] out NubComplexType? complexType)
|
||||
{
|
||||
if (this is NubSimpleType st)
|
||||
{
|
||||
complexType = null;
|
||||
simpleType = st;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this is NubComplexType ct)
|
||||
{
|
||||
complexType = ct;
|
||||
simpleType = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
throw new ArgumentException($"Type {this} is not a simple type, not a compex type");
|
||||
}
|
||||
|
||||
public abstract int Alignment(BoundDefinitionTable definitionTable);
|
||||
|
||||
public override bool Equals(object? obj) => obj is NubType other && Equals(other);
|
||||
|
||||
public abstract bool Equals(NubType? other);
|
||||
@@ -12,27 +49,48 @@ public abstract class NubType : IEquatable<NubType>
|
||||
public static bool operator !=(NubType? left, NubType? right) => !Equals(left, right);
|
||||
}
|
||||
|
||||
public class NubCStringType : NubType
|
||||
public enum StorageSize
|
||||
{
|
||||
public override string ToString() => "cstring";
|
||||
public override bool Equals(NubType? other) => other is NubCStringType;
|
||||
public override int GetHashCode() => HashCode.Combine(typeof(NubCStringType));
|
||||
Void,
|
||||
I8,
|
||||
I16,
|
||||
I32,
|
||||
I64,
|
||||
U8,
|
||||
U16,
|
||||
U32,
|
||||
U64,
|
||||
F32,
|
||||
F64
|
||||
}
|
||||
|
||||
public class NubStringType : NubType
|
||||
public abstract class NubSimpleType : NubType
|
||||
{
|
||||
public override string ToString() => "string";
|
||||
public override bool Equals(NubType? other) => other is NubStringType;
|
||||
public override int GetHashCode() => HashCode.Combine(typeof(NubStringType));
|
||||
public abstract StorageSize StorageSize { get; }
|
||||
|
||||
public override int Alignment(BoundDefinitionTable definitionTable)
|
||||
{
|
||||
return StorageSize switch
|
||||
{
|
||||
StorageSize.I64 or StorageSize.U64 or StorageSize.F64 => 8,
|
||||
StorageSize.I32 or StorageSize.U32 or StorageSize.F32 => 4,
|
||||
StorageSize.I16 or StorageSize.U16 => 2,
|
||||
StorageSize.I8 or StorageSize.U8 => 1,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(StorageSize))
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public class NubFuncType(NubType returnType, List<NubType> parameters) : NubType
|
||||
#region Simple types
|
||||
|
||||
public class NubFuncType(NubType returnType, List<NubType> parameters) : NubSimpleType
|
||||
{
|
||||
public NubType ReturnType { get; } = returnType;
|
||||
public List<NubType> Parameters { get; } = parameters;
|
||||
|
||||
public override string ToString() => $"func({string.Join(", ", Parameters)}): {ReturnType}";
|
||||
public override StorageSize StorageSize => StorageSize.U64;
|
||||
|
||||
public override string ToString() => $"func({string.Join(", ", Parameters)}): {ReturnType}";
|
||||
public override bool Equals(NubType? other) => other is NubFuncType func && ReturnType.Equals(func.ReturnType) && Parameters.SequenceEqual(func.Parameters);
|
||||
|
||||
public override int GetHashCode()
|
||||
@@ -49,48 +107,46 @@ public class NubFuncType(NubType returnType, List<NubType> parameters) : NubType
|
||||
}
|
||||
}
|
||||
|
||||
public class NubCustomType(string @namespace, string name) : NubType
|
||||
{
|
||||
public string Namespace { get; } = @namespace;
|
||||
public string Name { get; } = name;
|
||||
|
||||
public override string ToString() => $"{Namespace}::{Name}";
|
||||
|
||||
public override bool Equals(NubType? other) => other is NubCustomType custom && Namespace == custom.Namespace && Name == custom.Name;
|
||||
public override int GetHashCode() => HashCode.Combine(typeof(NubCustomType), Namespace, Name);
|
||||
}
|
||||
|
||||
public class NubPointerType(NubType baseType) : NubType
|
||||
public class NubPointerType(NubType baseType) : NubSimpleType
|
||||
{
|
||||
public NubType BaseType { get; } = baseType;
|
||||
|
||||
public override string ToString() => "^" + BaseType;
|
||||
public override StorageSize StorageSize => StorageSize.U64;
|
||||
|
||||
public override string ToString() => "^" + BaseType;
|
||||
public override bool Equals(NubType? other) => other is NubPointerType pointer && BaseType.Equals(pointer.BaseType);
|
||||
public override int GetHashCode() => HashCode.Combine(typeof(NubPointerType), BaseType);
|
||||
}
|
||||
|
||||
public class NubArrayType(NubType elementType) : NubType
|
||||
public class NubVoidType : NubSimpleType
|
||||
{
|
||||
public NubType ElementType { get; } = elementType;
|
||||
public override StorageSize StorageSize => StorageSize.Void;
|
||||
|
||||
public override string ToString() => "[]" + ElementType;
|
||||
|
||||
public override bool Equals(NubType? other) => other is NubArrayType array && ElementType.Equals(array.ElementType);
|
||||
public override int GetHashCode() => HashCode.Combine(typeof(NubArrayType), ElementType);
|
||||
}
|
||||
|
||||
public class NubVoidType : NubType
|
||||
{
|
||||
public override string ToString() => "void";
|
||||
public override bool Equals(NubType? other) => other is NubVoidType;
|
||||
public override int GetHashCode() => HashCode.Combine(typeof(NubVoidType));
|
||||
}
|
||||
|
||||
public class NubPrimitiveType(PrimitiveTypeKind kind) : NubType
|
||||
public class NubPrimitiveType(PrimitiveTypeKind kind) : NubSimpleType
|
||||
{
|
||||
public PrimitiveTypeKind Kind { get; } = kind;
|
||||
|
||||
public override StorageSize StorageSize => Kind switch
|
||||
{
|
||||
PrimitiveTypeKind.I8 => StorageSize.I8,
|
||||
PrimitiveTypeKind.I16 => StorageSize.I16,
|
||||
PrimitiveTypeKind.I32 => StorageSize.I32,
|
||||
PrimitiveTypeKind.I64 => StorageSize.I64,
|
||||
PrimitiveTypeKind.U8 => StorageSize.U8,
|
||||
PrimitiveTypeKind.U16 => StorageSize.U16,
|
||||
PrimitiveTypeKind.U32 => StorageSize.U32,
|
||||
PrimitiveTypeKind.U64 => StorageSize.U64,
|
||||
PrimitiveTypeKind.F64 => StorageSize.F64,
|
||||
PrimitiveTypeKind.F32 => StorageSize.F32,
|
||||
PrimitiveTypeKind.Bool => StorageSize.U8,
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
};
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Kind switch
|
||||
@@ -131,3 +187,85 @@ public enum PrimitiveTypeKind
|
||||
F32,
|
||||
Bool
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public abstract class NubComplexType : NubType;
|
||||
|
||||
#region Complex types
|
||||
|
||||
public class NubCStringType : NubComplexType
|
||||
{
|
||||
public override int Alignment(BoundDefinitionTable definitionTable) => 8;
|
||||
|
||||
public override string ToString() => "cstring";
|
||||
public override bool Equals(NubType? other) => other is NubCStringType;
|
||||
public override int GetHashCode() => HashCode.Combine(typeof(NubCStringType));
|
||||
}
|
||||
|
||||
public class NubStringType : NubComplexType
|
||||
{
|
||||
public override int Alignment(BoundDefinitionTable definitionTable) => 8;
|
||||
|
||||
public override string ToString() => "string";
|
||||
public override bool Equals(NubType? other) => other is NubStringType;
|
||||
public override int GetHashCode() => HashCode.Combine(typeof(NubStringType));
|
||||
}
|
||||
|
||||
public class NubCustomType(string @namespace, string name) : NubComplexType
|
||||
{
|
||||
public string Namespace { get; } = @namespace;
|
||||
public string Name { get; } = name;
|
||||
|
||||
public CustomTypeKind Kind(BoundDefinitionTable definitionTable)
|
||||
{
|
||||
if (definitionTable.GetStructs().Any(x => x.Namespace == Namespace && x.Name == Name))
|
||||
{
|
||||
return CustomTypeKind.Struct;
|
||||
}
|
||||
|
||||
if (definitionTable.GetTraits().Any(x => x.Namespace == Namespace && x.Name == Name))
|
||||
{
|
||||
return CustomTypeKind.Trait;
|
||||
}
|
||||
|
||||
throw new ArgumentException($"Definition table does not have any type information for {this}");
|
||||
}
|
||||
|
||||
public override int Alignment(BoundDefinitionTable definitionTable)
|
||||
{
|
||||
switch (Kind(definitionTable))
|
||||
{
|
||||
case CustomTypeKind.Struct:
|
||||
return definitionTable.LookupStruct(Namespace, Name).Fields.Max(f => f.Type.Alignment(definitionTable));
|
||||
case CustomTypeKind.Trait:
|
||||
return 8;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString() => $"{Namespace}::{Name}";
|
||||
public override bool Equals(NubType? other) => other is NubCustomType custom && Namespace == custom.Namespace && Name == custom.Name;
|
||||
public override int GetHashCode() => HashCode.Combine(typeof(NubCustomType), Namespace, Name);
|
||||
}
|
||||
|
||||
public enum CustomTypeKind
|
||||
{
|
||||
Struct,
|
||||
Trait
|
||||
}
|
||||
|
||||
public class NubArrayType(NubType elementType) : NubComplexType
|
||||
{
|
||||
public NubType ElementType { get; } = elementType;
|
||||
|
||||
public override int Alignment(BoundDefinitionTable definitionTable) => 8;
|
||||
|
||||
public override string ToString() => "[]" + ElementType;
|
||||
|
||||
public override bool Equals(NubType? other) => other is NubArrayType array && ElementType.Equals(array.ElementType);
|
||||
public override int GetHashCode() => HashCode.Combine(typeof(NubArrayType), ElementType);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -1,4 +1,3 @@
|
||||
using System.Diagnostics;
|
||||
using Common;
|
||||
using NubLang.Diagnostics;
|
||||
using NubLang.Syntax.Node;
|
||||
@@ -14,8 +13,8 @@ public sealed class Binder
|
||||
private readonly DefinitionTable _definitionTable;
|
||||
|
||||
// TODO: Implement proper variable tracking and scoping
|
||||
private Dictionary<string, BoundNubType> _variables = new();
|
||||
private BoundNubType? _functionReturnType;
|
||||
private Dictionary<string, NubType> _variables = new();
|
||||
private NubType? _functionReturnType;
|
||||
|
||||
public Binder(SyntaxTree syntaxTree, DefinitionTable definitionTable)
|
||||
{
|
||||
@@ -70,14 +69,14 @@ public sealed class Binder
|
||||
|
||||
foreach (var parameter in function.Parameters)
|
||||
{
|
||||
_variables[parameter.Name] = BindType(parameter.Type);
|
||||
parameters.Add(new BoundFuncParameterNode(parameter.Tokens, parameter.Name, BindType(parameter.Type)));
|
||||
_variables[parameter.Name] = parameter.Type;
|
||||
parameters.Add(new BoundFuncParameterNode(parameter.Tokens, parameter.Name, parameter.Type));
|
||||
}
|
||||
|
||||
functions.Add(new BoundTraitFuncImplNode(function.Tokens, function.Name, parameters, BindType(function.ReturnType), BindBlock(function.Body)));
|
||||
functions.Add(new BoundTraitFuncImplNode(function.Tokens, function.Name, parameters, function.ReturnType, BindBlock(function.Body)));
|
||||
}
|
||||
|
||||
return new BoundTraitImplNode(node.Tokens, node.Namespace, BindType(node.TraitType), BindType(node.ForType), functions);
|
||||
return new BoundTraitImplNode(node.Tokens, node.Namespace, node.TraitType, node.ForType, functions);
|
||||
}
|
||||
|
||||
private BoundTraitNode BindTraitDefinition(TraitNode node)
|
||||
@@ -90,10 +89,10 @@ public sealed class Binder
|
||||
|
||||
foreach (var parameter in function.Parameters)
|
||||
{
|
||||
parameters.Add(new BoundFuncParameterNode(parameter.Tokens, parameter.Name, BindType(parameter.Type)));
|
||||
parameters.Add(new BoundFuncParameterNode(parameter.Tokens, parameter.Name, parameter.Type));
|
||||
}
|
||||
|
||||
functions.Add(new BoundTraitFuncNode(node.Tokens, function.Name, parameters, BindType(function.ReturnType)));
|
||||
functions.Add(new BoundTraitFuncNode(node.Tokens, function.Name, parameters, function.ReturnType));
|
||||
}
|
||||
|
||||
return new BoundTraitNode(node.Tokens, node.Namespace, node.Name, functions);
|
||||
@@ -109,10 +108,10 @@ public sealed class Binder
|
||||
|
||||
if (field.Value.HasValue)
|
||||
{
|
||||
value = BindExpression(field.Value.Value, BindType(field.Type));
|
||||
value = BindExpression(field.Value.Value, field.Type);
|
||||
}
|
||||
|
||||
structFields.Add(new BoundStructFieldNode(field.Tokens, field.Index, field.Name, BindType(field.Type), value));
|
||||
structFields.Add(new BoundStructFieldNode(field.Tokens, field.Index, field.Name, field.Type, value));
|
||||
}
|
||||
|
||||
return new BoundStructNode(node.Tokens, node.Namespace, node.Name, structFields);
|
||||
@@ -124,28 +123,28 @@ public sealed class Binder
|
||||
|
||||
foreach (var parameter in node.Parameters)
|
||||
{
|
||||
parameters.Add(new BoundFuncParameterNode(parameter.Tokens, parameter.Name, BindType(parameter.Type)));
|
||||
parameters.Add(new BoundFuncParameterNode(parameter.Tokens, parameter.Name, parameter.Type));
|
||||
}
|
||||
|
||||
return new BoundExternFuncNode(node.Tokens, node.Namespace, node.Name, node.CallName, parameters, BindType(node.ReturnType));
|
||||
return new BoundExternFuncNode(node.Tokens, node.Namespace, node.Name, node.CallName, parameters, node.ReturnType);
|
||||
}
|
||||
|
||||
private BoundLocalFuncNode BindLocalFuncDefinition(LocalFuncNode node)
|
||||
{
|
||||
_variables.Clear();
|
||||
_functionReturnType = BindType(node.ReturnType);
|
||||
_functionReturnType = node.ReturnType;
|
||||
|
||||
var parameters = new List<BoundFuncParameterNode>();
|
||||
|
||||
foreach (var parameter in node.Parameters)
|
||||
{
|
||||
_variables[parameter.Name] = BindType(parameter.Type);
|
||||
parameters.Add(new BoundFuncParameterNode(parameter.Tokens, parameter.Name, BindType(parameter.Type)));
|
||||
_variables[parameter.Name] = parameter.Type;
|
||||
parameters.Add(new BoundFuncParameterNode(parameter.Tokens, parameter.Name, parameter.Type));
|
||||
}
|
||||
|
||||
var body = BindBlock(node.Body);
|
||||
|
||||
return new BoundLocalFuncNode(node.Tokens, node.Namespace, node.Name, parameters, body, BindType(node.ReturnType), node.Exported);
|
||||
return new BoundLocalFuncNode(node.Tokens, node.Namespace, node.Name, parameters, body, node.ReturnType, node.Exported);
|
||||
}
|
||||
|
||||
private BoundBlock BindBlock(BlockNode node)
|
||||
@@ -206,7 +205,7 @@ public sealed class Binder
|
||||
);
|
||||
}
|
||||
|
||||
return new BoundIfNode(statement.Tokens, BindExpression(statement.Condition, BoundNubPrimitiveType.Bool), BindBlock(statement.Body), elseStatement);
|
||||
return new BoundIfNode(statement.Tokens, BindExpression(statement.Condition, new NubPrimitiveType(PrimitiveTypeKind.Bool)), BindBlock(statement.Body), elseStatement);
|
||||
}
|
||||
|
||||
private BoundReturnNode BindReturn(ReturnNode statement)
|
||||
@@ -228,11 +227,11 @@ public sealed class Binder
|
||||
|
||||
private BoundVariableDeclarationNode BindVariableDeclaration(VariableDeclarationNode statement)
|
||||
{
|
||||
BoundNubType? type = null;
|
||||
NubType? type = null;
|
||||
|
||||
if (statement.ExplicitType.HasValue)
|
||||
{
|
||||
type = BindType(statement.ExplicitType.Value);
|
||||
type = statement.ExplicitType.Value;
|
||||
}
|
||||
|
||||
var assignment = Optional<BoundExpressionNode>.Empty();
|
||||
@@ -255,10 +254,10 @@ public sealed class Binder
|
||||
|
||||
private BoundWhileNode BindWhile(WhileNode statement)
|
||||
{
|
||||
return new BoundWhileNode(statement.Tokens, BindExpression(statement.Condition, BoundNubPrimitiveType.Bool), BindBlock(statement.Body));
|
||||
return new BoundWhileNode(statement.Tokens, BindExpression(statement.Condition, new NubPrimitiveType(PrimitiveTypeKind.Bool)), BindBlock(statement.Body));
|
||||
}
|
||||
|
||||
private BoundExpressionNode BindExpression(ExpressionNode node, BoundNubType? expectedType = null)
|
||||
private BoundExpressionNode BindExpression(ExpressionNode node, NubType? expectedType = null)
|
||||
{
|
||||
return node switch
|
||||
{
|
||||
@@ -281,7 +280,7 @@ public sealed class Binder
|
||||
private BoundAddressOfNode BindAddressOf(AddressOfNode expression)
|
||||
{
|
||||
var inner = BindExpression(expression.Expression);
|
||||
return new BoundAddressOfNode(expression.Tokens, new BoundNubPointerType(inner.Type), inner);
|
||||
return new BoundAddressOfNode(expression.Tokens, new NubPointerType(inner.Type), inner);
|
||||
}
|
||||
|
||||
private BoundAnonymousFuncNode BindAnonymousFunc(AnonymousFuncNode expression)
|
||||
@@ -290,24 +289,24 @@ public sealed class Binder
|
||||
|
||||
foreach (var parameter in expression.Parameters)
|
||||
{
|
||||
parameters.Add(new BoundFuncParameterNode(parameter.Tokens, parameter.Name, BindType(parameter.Type)));
|
||||
parameters.Add(new BoundFuncParameterNode(parameter.Tokens, parameter.Name, parameter.Type));
|
||||
}
|
||||
|
||||
var body = BindBlock(expression.Body);
|
||||
|
||||
return new BoundAnonymousFuncNode(expression.Tokens, new BoundNubFuncType(BindType(expression.ReturnType), parameters.Select(x => x.Type).ToList()), parameters, body, BindType(expression.ReturnType));
|
||||
return new BoundAnonymousFuncNode(expression.Tokens, new NubFuncType(expression.ReturnType, parameters.Select(x => x.Type).ToList()), parameters, body, expression.ReturnType);
|
||||
}
|
||||
|
||||
private BoundArrayIndexAccessNode BindArrayIndexAccess(ArrayIndexAccessNode expression)
|
||||
{
|
||||
var boundArray = BindExpression(expression.Target);
|
||||
var elementType = ((BoundNubArrayType)boundArray.Type).ElementType;
|
||||
return new BoundArrayIndexAccessNode(expression.Tokens, elementType, boundArray, BindExpression(expression.Index, BoundNubPrimitiveType.U64));
|
||||
var elementType = ((NubArrayType)boundArray.Type).ElementType;
|
||||
return new BoundArrayIndexAccessNode(expression.Tokens, elementType, boundArray, BindExpression(expression.Index, new NubPrimitiveType(PrimitiveTypeKind.U64)));
|
||||
}
|
||||
|
||||
private BoundArrayInitializerNode BindArrayInitializer(ArrayInitializerNode expression)
|
||||
{
|
||||
return new BoundArrayInitializerNode(expression.Tokens, new BoundNubArrayType(BindType(expression.ElementType)), BindExpression(expression.Capacity, BoundNubPrimitiveType.U64), BindType(expression.ElementType));
|
||||
return new BoundArrayInitializerNode(expression.Tokens, new NubArrayType(expression.ElementType), BindExpression(expression.Capacity, new NubPrimitiveType(PrimitiveTypeKind.U64)), expression.ElementType);
|
||||
}
|
||||
|
||||
private BoundBinaryExpressionNode BindBinaryExpression(BinaryExpressionNode expression)
|
||||
@@ -320,7 +319,7 @@ public sealed class Binder
|
||||
private BoundDereferenceNode BindDereference(DereferenceNode expression)
|
||||
{
|
||||
var boundExpression = BindExpression(expression.Expression);
|
||||
var dereferencedType = ((BoundNubPointerType)boundExpression.Type).BaseType;
|
||||
var dereferencedType = ((NubPointerType)boundExpression.Type).BaseType;
|
||||
return new BoundDereferenceNode(expression.Tokens, dereferencedType, boundExpression);
|
||||
}
|
||||
|
||||
@@ -328,7 +327,7 @@ public sealed class Binder
|
||||
{
|
||||
var boundExpression = BindExpression(expression.Expression);
|
||||
|
||||
var funcType = (BoundNubFuncType)boundExpression.Type;
|
||||
var funcType = (NubFuncType)boundExpression.Type;
|
||||
|
||||
var parameters = new List<BoundExpressionNode>();
|
||||
|
||||
@@ -361,7 +360,7 @@ public sealed class Binder
|
||||
var localFunc = localFuncs[0];
|
||||
|
||||
var type = new NubFuncType(localFunc.ReturnType, localFunc.Parameters.Select(p => p.Type).ToList());
|
||||
return new BoundLocalFuncIdentNode(expression.Tokens, BindType(type), @namespace, expression.Name);
|
||||
return new BoundLocalFuncIdentNode(expression.Tokens, type, @namespace, expression.Name);
|
||||
}
|
||||
|
||||
var externFuncs = _definitionTable.LookupExternFunc(@namespace, expression.Name).ToArray();
|
||||
@@ -375,7 +374,7 @@ public sealed class Binder
|
||||
var externFunc = externFuncs[0];
|
||||
|
||||
var type = new NubFuncType(externFunc.ReturnType, externFunc.Parameters.Select(p => p.Type).ToList());
|
||||
return new BoundExternFuncIdentNode(expression.Tokens, BindType(type), @namespace, expression.Name);
|
||||
return new BoundExternFuncIdentNode(expression.Tokens, type, @namespace, expression.Name);
|
||||
}
|
||||
|
||||
if (!expression.Namespace.HasValue)
|
||||
@@ -386,14 +385,14 @@ public sealed class Binder
|
||||
throw new BindException(Diagnostic.Error($"No identifier with then name {(expression.Namespace.HasValue ? $"{expression.Namespace.Value}::" : "")}{expression.Name} exists").Build());
|
||||
}
|
||||
|
||||
private BoundLiteralNode BindLiteral(LiteralNode expression, BoundNubType? expectedType = null)
|
||||
private BoundLiteralNode BindLiteral(LiteralNode expression, NubType? expectedType = null)
|
||||
{
|
||||
var type = expectedType ?? expression.Kind switch
|
||||
{
|
||||
LiteralKind.Integer => BoundNubPrimitiveType.I64,
|
||||
LiteralKind.Float => BoundNubPrimitiveType.F64,
|
||||
LiteralKind.String => new BoundNubStringType(),
|
||||
LiteralKind.Bool => BoundNubPrimitiveType.Bool,
|
||||
LiteralKind.Integer => new NubPrimitiveType(PrimitiveTypeKind.I64),
|
||||
LiteralKind.Float => new NubPrimitiveType(PrimitiveTypeKind.F64),
|
||||
LiteralKind.String => new NubStringType(),
|
||||
LiteralKind.Bool => new NubPrimitiveType(PrimitiveTypeKind.Bool),
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
};
|
||||
|
||||
@@ -404,7 +403,7 @@ public sealed class Binder
|
||||
{
|
||||
var boundExpression = BindExpression(expression.Target);
|
||||
|
||||
var traitFuncImpls = _definitionTable.LookupTraitFuncImpl(UnbindType(boundExpression.Type), expression.Member).ToArray();
|
||||
var traitFuncImpls = _definitionTable.LookupTraitFuncImpl(boundExpression.Type, expression.Member).ToArray();
|
||||
if (traitFuncImpls.Length > 0)
|
||||
{
|
||||
if (traitFuncImpls.Length > 1)
|
||||
@@ -414,18 +413,18 @@ public sealed class Binder
|
||||
|
||||
var impl = traitFuncImpls[0];
|
||||
|
||||
var type = new BoundNubFuncType(BindType(impl.ReturnType), impl.Parameters.Select(p => BindType(p.Type)).ToList());
|
||||
var type = new NubFuncType(impl.ReturnType, impl.Parameters.Select(p => p.Type).ToList());
|
||||
return new BoundTraitImplFuncAccessNode(expression.Tokens, type, boundExpression, expression.Member);
|
||||
}
|
||||
|
||||
if (boundExpression.Type is BoundNubTraitType traitType)
|
||||
if (boundExpression.Type is NubCustomType customType)
|
||||
{
|
||||
var traits = _definitionTable.LookupTrait(traitType.Namespace, traitType.Name).ToArray();
|
||||
var traits = _definitionTable.LookupTrait(customType.Namespace, customType.Name).ToArray();
|
||||
if (traits.Length > 0)
|
||||
{
|
||||
if (traits.Length > 1)
|
||||
{
|
||||
throw new BindException(Diagnostic.Error($"Trait {traitType.Namespace}::{traitType.Name} has multiple definitions").Build());
|
||||
throw new BindException(Diagnostic.Error($"Trait {customType.Namespace}::{customType.Name} has multiple definitions").Build());
|
||||
}
|
||||
|
||||
var trait = traits[0];
|
||||
@@ -440,20 +439,17 @@ public sealed class Binder
|
||||
|
||||
var traitFunc = traitFuncs[0];
|
||||
|
||||
var type = new BoundNubFuncType(BindType(traitFunc.ReturnType), traitFunc.Parameters.Select(p => BindType(p.Type)).ToList());
|
||||
return new BoundTraitFuncAccessNode(expression.Tokens, type, traitType, boundExpression, expression.Member);
|
||||
var type = new NubFuncType(traitFunc.ReturnType, traitFunc.Parameters.Select(p => p.Type).ToList());
|
||||
return new BoundTraitFuncAccessNode(expression.Tokens, type, customType, boundExpression, expression.Member);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (boundExpression.Type is BoundNubStructType structType)
|
||||
{
|
||||
var structs = _definitionTable.LookupStruct(structType.Namespace, structType.Name).ToArray();
|
||||
var structs = _definitionTable.LookupStruct(customType.Namespace, customType.Name).ToArray();
|
||||
if (structs.Length > 0)
|
||||
{
|
||||
if (structs.Length > 1)
|
||||
{
|
||||
throw new BindException(Diagnostic.Error($"Struct {structType.Namespace}::{structType.Name} has multiple definitions").Build());
|
||||
throw new BindException(Diagnostic.Error($"Struct {customType.Namespace}::{customType.Name} has multiple definitions").Build());
|
||||
}
|
||||
|
||||
var @struct = structs[0];
|
||||
@@ -468,7 +464,7 @@ public sealed class Binder
|
||||
|
||||
var field = fields[0];
|
||||
|
||||
return new BoundStructFieldAccessNode(expression.Tokens, BindType(field.Type), structType, boundExpression, expression.Member);
|
||||
return new BoundStructFieldAccessNode(expression.Tokens, field.Type, customType, boundExpression, expression.Member);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -513,23 +509,23 @@ public sealed class Binder
|
||||
throw new BindException(Diagnostic.Error($"Struct {@struct.Namespace}::{@struct.Name} has multiple fields with the name {field}").Build());
|
||||
}
|
||||
|
||||
initializers[field] = BindExpression(initializer, BindType(fields[0].Type));
|
||||
initializers[field] = BindExpression(initializer, fields[0].Type);
|
||||
}
|
||||
|
||||
return new BoundStructInitializerNode(expression.Tokens, BindType(structType), new BoundNubStructType(@struct.Namespace, @struct.Name), initializers);
|
||||
return new BoundStructInitializerNode(expression.Tokens, structType, new NubCustomType(@struct.Namespace, @struct.Name), initializers);
|
||||
}
|
||||
|
||||
private BoundUnaryExpressionNode BindUnaryExpression(Node_UnaryExpressionNode expression)
|
||||
{
|
||||
var boundOperand = BindExpression(expression.Operand);
|
||||
|
||||
BoundNubType? type = null;
|
||||
NubType? type = null;
|
||||
|
||||
switch (expression.Operator)
|
||||
{
|
||||
case UnaryExpressionOperator.Negate:
|
||||
{
|
||||
boundOperand = BindExpression(expression.Operand, BoundNubPrimitiveType.I64);
|
||||
boundOperand = BindExpression(expression.Operand, new NubPrimitiveType(PrimitiveTypeKind.I64));
|
||||
|
||||
if (boundOperand.Type.IsNumber)
|
||||
{
|
||||
@@ -540,9 +536,9 @@ public sealed class Binder
|
||||
}
|
||||
case UnaryExpressionOperator.Invert:
|
||||
{
|
||||
boundOperand = BindExpression(expression.Operand, BoundNubPrimitiveType.Bool);
|
||||
boundOperand = BindExpression(expression.Operand, new NubPrimitiveType(PrimitiveTypeKind.Bool));
|
||||
|
||||
type = new BoundNubPrimitiveType(PrimitiveTypeKind.Bool);
|
||||
type = new NubPrimitiveType(PrimitiveTypeKind.Bool);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -554,82 +550,6 @@ public sealed class Binder
|
||||
|
||||
return new BoundUnaryExpressionNode(expression.Tokens, type, expression.Operator, boundOperand);
|
||||
}
|
||||
|
||||
private BoundNubType BindType(NubType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case NubCustomType customType:
|
||||
{
|
||||
var structs = _definitionTable.LookupStruct(customType.Namespace, customType.Name).ToArray();
|
||||
if (structs.Length > 1)
|
||||
{
|
||||
throw new BindException(Diagnostic.Error($"Struct {type} has multiple definitions").Build());
|
||||
}
|
||||
|
||||
var traits = _definitionTable.LookupTrait(customType.Namespace, customType.Name).ToArray();
|
||||
if (traits.Length > 1)
|
||||
{
|
||||
throw new BindException(Diagnostic.Error($"Trait {type} has multiple definitions").Build());
|
||||
}
|
||||
|
||||
if (structs.Length == 0 && traits.Length == 0)
|
||||
{
|
||||
throw new BindException(Diagnostic.Error($"Failed to resolve type {type} to a struct or trait").Build());
|
||||
}
|
||||
|
||||
if (structs.Length > 0 && traits.Length > 0)
|
||||
{
|
||||
throw new BindException(Diagnostic.Error($"Unable to determine if type {type} is a struct or trait").WithHelp($"Make {type} is not defined as bot a struct and trait").Build());
|
||||
}
|
||||
|
||||
if (structs.Length == 1)
|
||||
{
|
||||
return new BoundNubStructType(customType.Namespace, customType.Name);
|
||||
}
|
||||
|
||||
if (traits.Length == 1)
|
||||
{
|
||||
return new BoundNubTraitType(customType.Namespace, customType.Name);
|
||||
}
|
||||
|
||||
throw new UnreachableException();
|
||||
}
|
||||
case NubArrayType arrayType:
|
||||
return new BoundNubArrayType(BindType(arrayType.ElementType));
|
||||
case NubCStringType:
|
||||
return new BoundNubCStringType();
|
||||
case NubStringType:
|
||||
return new BoundNubStringType();
|
||||
case NubFuncType funcType:
|
||||
return new BoundNubFuncType(BindType(funcType.ReturnType), funcType.Parameters.Select(BindType).ToList());
|
||||
case NubPointerType pointerType:
|
||||
return new BoundNubPointerType(BindType(pointerType.BaseType));
|
||||
case NubPrimitiveType primitiveType:
|
||||
return new BoundNubPrimitiveType(primitiveType.Kind);
|
||||
case NubVoidType:
|
||||
return new BoundNubVoidType();
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(type));
|
||||
}
|
||||
}
|
||||
|
||||
private NubType UnbindType(BoundNubType type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
BoundNubArrayType arrayType => new NubArrayType(UnbindType(arrayType.ElementType)),
|
||||
BoundNubCStringType => new NubCStringType(),
|
||||
BoundNubStringType => new NubStringType(),
|
||||
BoundNubStructType structType => new NubCustomType(structType.Namespace, structType.Name),
|
||||
BoundNubTraitType traitType => new NubCustomType(traitType.Namespace, traitType.Name),
|
||||
BoundNubFuncType funcType => new NubFuncType(UnbindType(funcType.ReturnType), funcType.Parameters.Select(UnbindType).ToList()),
|
||||
BoundNubPointerType pointerType => new NubPointerType(UnbindType(pointerType.BaseType)),
|
||||
BoundNubPrimitiveType primitiveType => new NubPrimitiveType(primitiveType.Kind),
|
||||
BoundNubVoidType => new NubVoidType(),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(type))
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public class BindException : Exception
|
||||
|
||||
@@ -4,7 +4,7 @@ using NubLang.Syntax.Tokenization;
|
||||
namespace NubLang.Syntax.Node;
|
||||
|
||||
public record FuncParameterNode(IEnumerable<Token> Tokens, string Name, NubType Type) : DefinitionNode(Tokens);
|
||||
public record BoundFuncParameterNode(IEnumerable<Token> Tokens, string Name, BoundNubType Type) : DefinitionNode(Tokens);
|
||||
public record BoundFuncParameterNode(IEnumerable<Token> Tokens, string Name, NubType Type) : DefinitionNode(Tokens);
|
||||
|
||||
public abstract record TopLevelNode(IEnumerable<Token> Tokens, string Namespace) : Node(Tokens);
|
||||
public abstract record BoundTopLevelNode(IEnumerable<Token> Tokens, string Namespace) : BoundNode(Tokens);
|
||||
@@ -13,25 +13,25 @@ public abstract record DefinitionNode(IEnumerable<Token> Tokens) : Node(Tokens);
|
||||
public abstract record BoundDefinitionNode(IEnumerable<Token> Tokens) : BoundNode(Tokens);
|
||||
|
||||
public record LocalFuncNode(IEnumerable<Token> Tokens, string Namespace, string Name, List<FuncParameterNode> Parameters, BlockNode Body, NubType ReturnType, bool Exported) : TopLevelNode(Tokens, Namespace);
|
||||
public record BoundLocalFuncNode(IEnumerable<Token> Tokens, string Namespace, string Name, List<BoundFuncParameterNode> Parameters, BoundBlock Body, BoundNubType ReturnType, bool Exported) : BoundTopLevelNode(Tokens, Namespace);
|
||||
public record BoundLocalFuncNode(IEnumerable<Token> Tokens, string Namespace, string Name, List<BoundFuncParameterNode> Parameters, BoundBlock Body, NubType ReturnType, bool Exported) : BoundTopLevelNode(Tokens, Namespace);
|
||||
|
||||
public record ExternFuncNode(IEnumerable<Token> Tokens, string Namespace, string Name, string CallName, List<FuncParameterNode> Parameters, NubType ReturnType) : TopLevelNode(Tokens, Namespace);
|
||||
public record BoundExternFuncNode(IEnumerable<Token> Tokens, string Namespace, string Name, string CallName, List<BoundFuncParameterNode> Parameters, BoundNubType ReturnType) : BoundTopLevelNode(Tokens, Namespace);
|
||||
public record BoundExternFuncNode(IEnumerable<Token> Tokens, string Namespace, string Name, string CallName, List<BoundFuncParameterNode> Parameters, NubType ReturnType) : BoundTopLevelNode(Tokens, Namespace);
|
||||
|
||||
public record StructFieldNode(IEnumerable<Token> Tokens, int Index, string Name, NubType Type, Optional<ExpressionNode> Value) : DefinitionNode(Tokens);
|
||||
public record StructNode(IEnumerable<Token> Tokens, string Namespace, string Name, List<StructFieldNode> Fields) : TopLevelNode(Tokens, Namespace);
|
||||
|
||||
public record BoundStructFieldNode(IEnumerable<Token> Tokens, int Index, string Name, BoundNubType Type, Optional<BoundExpressionNode> Value) : BoundDefinitionNode(Tokens);
|
||||
public record BoundStructFieldNode(IEnumerable<Token> Tokens, int Index, string Name, NubType Type, Optional<BoundExpressionNode> Value) : BoundDefinitionNode(Tokens);
|
||||
public record BoundStructNode(IEnumerable<Token> Tokens, string Namespace, string Name, List<BoundStructFieldNode> Fields) : BoundTopLevelNode(Tokens, Namespace);
|
||||
|
||||
public record TraitFuncNode(IEnumerable<Token> Tokens, string Name, List<FuncParameterNode> Parameters, NubType ReturnType) : DefinitionNode(Tokens);
|
||||
public record TraitNode(IEnumerable<Token> Tokens, string Namespace, string Name, List<TraitFuncNode> Functions) : TopLevelNode(Tokens, Namespace);
|
||||
|
||||
public record BoundTraitFuncNode(IEnumerable<Token> Tokens, string Name, List<BoundFuncParameterNode> Parameters, BoundNubType ReturnType) : BoundDefinitionNode(Tokens);
|
||||
public record BoundTraitFuncNode(IEnumerable<Token> Tokens, string Name, List<BoundFuncParameterNode> Parameters, NubType ReturnType) : BoundDefinitionNode(Tokens);
|
||||
public record BoundTraitNode(IEnumerable<Token> Tokens, string Namespace, string Name, List<BoundTraitFuncNode> Functions) : BoundTopLevelNode(Tokens, Namespace);
|
||||
|
||||
public record TraitFuncImplNode(IEnumerable<Token> Tokens, string Name, List<FuncParameterNode> Parameters, NubType ReturnType, BlockNode Body) : DefinitionNode(Tokens);
|
||||
public record TraitImplNode(IEnumerable<Token> Tokens, string Namespace, NubType TraitType, NubType ForType, List<TraitFuncImplNode> Functions) : TopLevelNode(Tokens, Namespace);
|
||||
|
||||
public record BoundTraitFuncImplNode(IEnumerable<Token> Tokens, string Name, List<BoundFuncParameterNode> Parameters, BoundNubType ReturnType, BoundBlock Body) : BoundDefinitionNode(Tokens);
|
||||
public record BoundTraitImplNode(IEnumerable<Token> Tokens, string Namespace, BoundNubType TraitType, BoundNubType ForType, List<BoundTraitFuncImplNode> Functions) : BoundTopLevelNode(Tokens, Namespace);
|
||||
public record BoundTraitFuncImplNode(IEnumerable<Token> Tokens, string Name, List<BoundFuncParameterNode> Parameters, NubType ReturnType, BoundBlock Body) : BoundDefinitionNode(Tokens);
|
||||
public record BoundTraitImplNode(IEnumerable<Token> Tokens, string Namespace, NubType TraitType, NubType ForType, List<BoundTraitFuncImplNode> Functions) : BoundTopLevelNode(Tokens, Namespace);
|
||||
@@ -24,44 +24,44 @@ public enum BinaryExpressionOperator
|
||||
}
|
||||
|
||||
public abstract record ExpressionNode(IEnumerable<Token> Tokens) : Node(Tokens);
|
||||
public abstract record BoundExpressionNode(IEnumerable<Token> Tokens, BoundNubType Type) : BoundNode(Tokens);
|
||||
public abstract record BoundExpressionNode(IEnumerable<Token> Tokens, NubType Type) : BoundNode(Tokens);
|
||||
|
||||
public record BinaryExpressionNode(IEnumerable<Token> Tokens, ExpressionNode Left, BinaryExpressionOperator Operator, ExpressionNode Right) : ExpressionNode(Tokens);
|
||||
public record BoundBinaryExpressionNode(IEnumerable<Token> Tokens, BoundNubType Type, BoundExpressionNode Left, BinaryExpressionOperator Operator, BoundExpressionNode Right) : BoundExpressionNode(Tokens, Type);
|
||||
public record BoundBinaryExpressionNode(IEnumerable<Token> Tokens, NubType Type, BoundExpressionNode Left, BinaryExpressionOperator Operator, BoundExpressionNode Right) : BoundExpressionNode(Tokens, Type);
|
||||
|
||||
public record UnaryExpressionNode(IEnumerable<Token> Tokens, UnaryExpressionOperator Operator, ExpressionNode Operand) : ExpressionNode(Tokens);
|
||||
public record BoundUnaryExpressionNode(IEnumerable<Token> Tokens, BoundNubType Type, UnaryExpressionOperator Operator, BoundExpressionNode Operand) : BoundExpressionNode(Tokens, Type);
|
||||
public record BoundUnaryExpressionNode(IEnumerable<Token> Tokens, NubType Type, UnaryExpressionOperator Operator, BoundExpressionNode Operand) : BoundExpressionNode(Tokens, Type);
|
||||
|
||||
public record FuncCallNode(IEnumerable<Token> Tokens, ExpressionNode Expression, List<ExpressionNode> Parameters) : ExpressionNode(Tokens);
|
||||
public record BoundFuncCallNode(IEnumerable<Token> Tokens, BoundNubType Type, BoundExpressionNode Expression, List<BoundExpressionNode> Parameters) : BoundExpressionNode(Tokens, Type);
|
||||
public record BoundFuncCallNode(IEnumerable<Token> Tokens, NubType Type, BoundExpressionNode Expression, List<BoundExpressionNode> Parameters) : BoundExpressionNode(Tokens, Type);
|
||||
|
||||
public record IdentifierNode(IEnumerable<Token> Tokens, Optional<string> Namespace, string Name) : ExpressionNode(Tokens);
|
||||
public record BoundVariableIdentNode(IEnumerable<Token> Tokens, BoundNubType Type, string Name) : BoundExpressionNode(Tokens, Type);
|
||||
public record BoundLocalFuncIdentNode(IEnumerable<Token> Tokens, BoundNubType Type, string Namespace, string Name) : BoundExpressionNode(Tokens, Type);
|
||||
public record BoundExternFuncIdentNode(IEnumerable<Token> Tokens, BoundNubType Type, string Namespace, string Name) : BoundExpressionNode(Tokens, Type);
|
||||
public record BoundVariableIdentNode(IEnumerable<Token> Tokens, NubType Type, string Name) : BoundExpressionNode(Tokens, Type);
|
||||
public record BoundLocalFuncIdentNode(IEnumerable<Token> Tokens, NubType Type, string Namespace, string Name) : BoundExpressionNode(Tokens, Type);
|
||||
public record BoundExternFuncIdentNode(IEnumerable<Token> Tokens, NubType Type, string Namespace, string Name) : BoundExpressionNode(Tokens, Type);
|
||||
|
||||
public record ArrayInitializerNode(IEnumerable<Token> Tokens, ExpressionNode Capacity, NubType ElementType) : ExpressionNode(Tokens);
|
||||
public record BoundArrayInitializerNode(IEnumerable<Token> Tokens, BoundNubType Type, BoundExpressionNode Capacity, BoundNubType ElementType) : BoundExpressionNode(Tokens, Type);
|
||||
public record BoundArrayInitializerNode(IEnumerable<Token> Tokens, NubType Type, BoundExpressionNode Capacity, NubType ElementType) : BoundExpressionNode(Tokens, Type);
|
||||
|
||||
public record ArrayIndexAccessNode(IEnumerable<Token> Tokens, ExpressionNode Target, ExpressionNode Index) : ExpressionNode(Tokens);
|
||||
public record BoundArrayIndexAccessNode(IEnumerable<Token> Tokens, BoundNubType Type, BoundExpressionNode Target, BoundExpressionNode Index) : BoundExpressionNode(Tokens, Type);
|
||||
public record BoundArrayIndexAccessNode(IEnumerable<Token> Tokens, NubType Type, BoundExpressionNode Target, BoundExpressionNode Index) : BoundExpressionNode(Tokens, Type);
|
||||
|
||||
public record AnonymousFuncNode(IEnumerable<Token> Tokens, List<FuncParameterNode> Parameters, BlockNode Body, NubType ReturnType) : ExpressionNode(Tokens);
|
||||
public record BoundAnonymousFuncNode(IEnumerable<Token> Tokens, BoundNubType Type, List<BoundFuncParameterNode> Parameters, BoundBlock Body, BoundNubType ReturnType) : BoundExpressionNode(Tokens, Type);
|
||||
public record BoundAnonymousFuncNode(IEnumerable<Token> Tokens, NubType Type, List<BoundFuncParameterNode> Parameters, BoundBlock Body, NubType ReturnType) : BoundExpressionNode(Tokens, Type);
|
||||
|
||||
public record AddressOfNode(IEnumerable<Token> Tokens, ExpressionNode Expression) : ExpressionNode(Tokens);
|
||||
public record BoundAddressOfNode(IEnumerable<Token> Tokens, BoundNubType Type, BoundExpressionNode Expression) : BoundExpressionNode(Tokens, Type);
|
||||
public record BoundAddressOfNode(IEnumerable<Token> Tokens, NubType Type, BoundExpressionNode Expression) : BoundExpressionNode(Tokens, Type);
|
||||
|
||||
public record LiteralNode(IEnumerable<Token> Tokens, string Literal, LiteralKind Kind) : ExpressionNode(Tokens);
|
||||
public record BoundLiteralNode(IEnumerable<Token> Tokens, BoundNubType Type, string Literal, LiteralKind Kind) : BoundExpressionNode(Tokens, Type);
|
||||
public record BoundLiteralNode(IEnumerable<Token> Tokens, NubType Type, string Literal, LiteralKind Kind) : BoundExpressionNode(Tokens, Type);
|
||||
|
||||
public record MemberAccessNode(IEnumerable<Token> Tokens, ExpressionNode Target, string Member) : ExpressionNode(Tokens);
|
||||
public record BoundStructFieldAccessNode(IEnumerable<Token> Tokens, BoundNubType Type, BoundNubStructType StructType, BoundExpressionNode Target, string Field) : BoundExpressionNode(Tokens, Type);
|
||||
public record BoundTraitImplFuncAccessNode(IEnumerable<Token> Tokens, BoundNubType Type, BoundExpressionNode Target, string FuncName) : BoundExpressionNode(Tokens, Type);
|
||||
public record BoundTraitFuncAccessNode(IEnumerable<Token> Tokens, BoundNubType Type, BoundNubTraitType TraitType, BoundExpressionNode Target, string FuncName) : BoundExpressionNode(Tokens, Type);
|
||||
public record BoundStructFieldAccessNode(IEnumerable<Token> Tokens, NubType Type, NubCustomType StructType, BoundExpressionNode Target, string Field) : BoundExpressionNode(Tokens, Type);
|
||||
public record BoundTraitImplFuncAccessNode(IEnumerable<Token> Tokens, NubType Type, BoundExpressionNode Target, string FuncName) : BoundExpressionNode(Tokens, Type);
|
||||
public record BoundTraitFuncAccessNode(IEnumerable<Token> Tokens, NubType Type, NubCustomType TraitType, BoundExpressionNode Target, string FuncName) : BoundExpressionNode(Tokens, Type);
|
||||
|
||||
public record StructInitializerNode(IEnumerable<Token> Tokens, NubType StructType, Dictionary<string, ExpressionNode> Initializers) : ExpressionNode(Tokens);
|
||||
public record BoundStructInitializerNode(IEnumerable<Token> Tokens, BoundNubType Type, BoundNubStructType StructType, Dictionary<string, BoundExpressionNode> Initializers) : BoundExpressionNode(Tokens, Type);
|
||||
public record BoundStructInitializerNode(IEnumerable<Token> Tokens, NubType Type, NubCustomType StructType, Dictionary<string, BoundExpressionNode> Initializers) : BoundExpressionNode(Tokens, Type);
|
||||
|
||||
public record DereferenceNode(IEnumerable<Token> Tokens, ExpressionNode Expression) : ExpressionNode(Tokens);
|
||||
public record BoundDereferenceNode(IEnumerable<Token> Tokens, BoundNubType Type, BoundExpressionNode Expression) : BoundExpressionNode(Tokens, Type);
|
||||
public record BoundDereferenceNode(IEnumerable<Token> Tokens, NubType Type, BoundExpressionNode Expression) : BoundExpressionNode(Tokens, Type);
|
||||
@@ -20,7 +20,7 @@ public record IfNode(IEnumerable<Token> Tokens, ExpressionNode Condition, BlockN
|
||||
public record BoundIfNode(IEnumerable<Token> Tokens, BoundExpressionNode Condition, BoundBlock Body, Optional<Variant<BoundIfNode, BoundBlock>> Else) : BoundStatementNode(Tokens);
|
||||
|
||||
public record VariableDeclarationNode(IEnumerable<Token> Tokens, string Name, Optional<NubType> ExplicitType, Optional<ExpressionNode> Assignment) : StatementNode(Tokens);
|
||||
public record BoundVariableDeclarationNode(IEnumerable<Token> Tokens, string Name, Optional<BoundExpressionNode> Assignment, BoundNubType Type) : BoundStatementNode(Tokens);
|
||||
public record BoundVariableDeclarationNode(IEnumerable<Token> Tokens, string Name, Optional<BoundExpressionNode> Assignment, NubType Type) : BoundStatementNode(Tokens);
|
||||
|
||||
public record ContinueNode(IEnumerable<Token> Tokens) : StatementNode(Tokens);
|
||||
public record BoundContinueNode(IEnumerable<Token> Tokens) : BoundStatementNode(Tokens);
|
||||
|
||||
Reference in New Issue
Block a user