This commit is contained in:
nub31
2025-11-03 13:46:25 +01:00
parent 085f7a1a6a
commit f231a45285
4 changed files with 133 additions and 63 deletions

View File

@@ -581,9 +581,25 @@ public class SizeNode(List<Token> tokens, NubType targetType) : RValue(tokens, n
}
}
public class CastNode(List<Token> tokens, NubType type, ExpressionNode value) : RValue(tokens, type)
public class CastNode(List<Token> tokens, NubType type, ExpressionNode value, CastNode.Conversion conversionType) : RValue(tokens, type)
{
public enum Conversion
{
IntToInt,
FloatToFloat,
IntToFloat,
FloatToInt,
PointerToPointer,
PointerToUInt64,
UInt64ToPointer,
ConstArrayToArray,
ConstArrayToSlice,
}
public ExpressionNode Value { get; } = value;
public Conversion ConversionType { get; } = conversionType;
public override IEnumerable<Node> Children()
{

View File

@@ -322,9 +322,9 @@ public sealed class TypeChecker
return result;
}
if (IsCastAllowed(result.Type, expectedType))
if (IsCastAllowed(result.Type, expectedType, out var conversion))
{
return new CastNode(result.Tokens, expectedType, result);
return new CastNode(result.Tokens, expectedType, result, conversion);
}
}
@@ -354,26 +354,39 @@ public sealed class TypeChecker
return value;
}
if (!IsCastAllowed(value.Type, expectedType, false))
if (!IsCastAllowed(value.Type, expectedType, out var conversion, false))
{
throw new CompileException(Diagnostic
.Error($"Cannot cast from {value.Type} to {expectedType}")
.Build());
}
return new CastNode(expression.Tokens, expectedType, value);
return new CastNode(expression.Tokens, expectedType, value, conversion);
}
private static bool IsCastAllowed(NubType from, NubType to, bool strict = true)
private static bool IsCastAllowed(NubType from, NubType to, out CastNode.Conversion conversion, bool strict = true)
{
// note(nub31): Implicit casts
switch (from)
{
case NubIntType fromInt when to is NubIntType toInt && fromInt.Width < toInt.Width:
{
conversion = CastNode.Conversion.IntToInt;
return true;
}
case NubPointerType when to is NubPointerType { BaseType: NubVoidType }:
{
conversion = CastNode.Conversion.PointerToPointer;
return true;
}
case NubConstArrayType constArrayType1 when to is NubArrayType arrayType && constArrayType1.ElementType == arrayType.ElementType:
{
conversion = CastNode.Conversion.ConstArrayToArray;
return true;
}
case NubConstArrayType constArrayType3 when to is NubSliceType sliceType2 && constArrayType3.ElementType == sliceType2.ElementType:
{
conversion = CastNode.Conversion.ConstArrayToSlice;
return true;
}
}
@@ -384,19 +397,44 @@ public sealed class TypeChecker
switch (from)
{
case NubIntType when to is NubIntType:
case NubIntType when to is NubFloatType:
case NubFloatType when to is NubIntType:
case NubFloatType when to is NubFloatType:
case NubPointerType when to is NubPointerType:
case NubPointerType when to is NubIntType:
case NubIntType when to is NubPointerType:
{
conversion = CastNode.Conversion.IntToInt;
return true;
}
case NubIntType when to is NubFloatType:
{
conversion = CastNode.Conversion.IntToFloat;
return true;
}
case NubFloatType when to is NubIntType:
{
conversion = CastNode.Conversion.FloatToInt;
return true;
}
case NubFloatType when to is NubFloatType:
{
conversion = CastNode.Conversion.FloatToFloat;
return true;
}
case NubPointerType when to is NubPointerType:
{
conversion = CastNode.Conversion.PointerToPointer;
return true;
}
case NubPointerType when to is NubIntType { Signed: false, Width: 64 }:
{
conversion = CastNode.Conversion.PointerToUInt64;
return true;
}
case NubIntType { Signed: false, Width: 64 } when to is NubPointerType:
{
conversion = CastNode.Conversion.UInt64ToPointer;
return true;
}
}
}
conversion = default;
return false;
}