This commit is contained in:
nub31
2025-10-22 20:16:50 +02:00
parent 1fb88f2073
commit caacf3d402
7 changed files with 169 additions and 43 deletions

View File

@@ -122,10 +122,14 @@ public record VariableIdentifierNode(List<Token> Tokens, NubType Type, string Na
public record FuncIdentifierNode(List<Token> Tokens, NubType Type, string Module, string Name, string? ExternSymbol) : RValueExpressionNode(Tokens, Type);
public record ArrayInitializerNode(List<Token> Tokens, NubType Type, ExpressionNode Capacity, NubType ElementType) : RValueExpressionNode(Tokens, Type);
public record ArrayInitializerNode(List<Token> Tokens, NubType Type, List<ExpressionNode> Values) : RValueExpressionNode(Tokens, Type);
public record ConstArrayInitializerNode(List<Token> Tokens, NubType Type, List<ExpressionNode> Values) : RValueExpressionNode(Tokens, Type);
public record ArrayIndexAccessNode(List<Token> Tokens, NubType Type, ExpressionNode Target, ExpressionNode Index) : LValueExpressionNode(Tokens, Type);
public record ConstArrayIndexAccessNode(List<Token> Tokens, NubType Type, ExpressionNode Target, ExpressionNode Index) : LValueExpressionNode(Tokens, Type);
public record SliceIndexAccessNode(List<Token> Tokens, NubType Type, ExpressionNode Target, ExpressionNode Index) : LValueExpressionNode(Tokens, Type);
public record AddressOfNode(List<Token> Tokens, NubType Type, LValueExpressionNode LValue) : RValueExpressionNode(Tokens, Type);
@@ -140,14 +144,14 @@ public record ConvertIntNode(List<Token> Tokens, ExpressionNode Value, int Start
public record ConvertFloatNode(List<Token> Tokens, ExpressionNode Value, int StartWidth, int TargetWidth) : RValueExpressionNode(Tokens, new NubFloatType(TargetWidth));
public record ConvertStringToCStringNode(List<Token> Tokens, ExpressionNode Value) : RValueExpressionNode(Tokens, new NubCStringType());
public record ConvertCStringToStringNode(List<Token> Tokens, ExpressionNode Value) : RValueExpressionNode(Tokens, new NubStringType());
public record SizeBuiltinNode(List<Token> Tokens, NubType Type, NubType TargetType) : RValueExpressionNode(Tokens, Type);
public record FloatToIntBuiltinNode(List<Token> Tokens, NubType Type, ExpressionNode Value, NubFloatType ValueType, NubIntType TargetType) : RValueExpressionNode(Tokens, Type);
public record ConstArrayToSliceNode(List<Token> Tokens, NubType Type, ExpressionNode Array) : RValueExpressionNode(Tokens, Type);
public record EnumReferenceIntermediateNode(List<Token> Tokens, string Module, string Name) : IntermediateExpression(Tokens);
#endregion

View File

@@ -272,8 +272,8 @@ public sealed class TypeChecker
default:
{
throw new TypeCheckerException(Diagnostic
.Error($"For statement not supported for type {target.Type}")
.At(forSyntax)
.Error($"Cannot iterate over type {target.Type} which does not have size information")
.At(forSyntax.Target)
.Build());
}
}
@@ -292,7 +292,7 @@ public sealed class TypeChecker
private ExpressionNode CheckExpression(ExpressionSyntax node, NubType? expectedType = null)
{
return node switch
var result = node switch
{
AddressOfSyntax expression => CheckAddressOf(expression, expectedType),
ArrayIndexAccessSyntax expression => CheckArrayIndexAccess(expression, expectedType),
@@ -314,6 +314,40 @@ public sealed class TypeChecker
FloatToIntBuiltinSyntax expression => CheckFloatToInt(expression, expectedType),
_ => throw new ArgumentOutOfRangeException(nameof(node))
};
switch (expectedType)
{
// note(nub31): Implicit conversion of const array to unsized array
case NubArrayType when result.Type is NubConstArrayType constArrayType:
{
return result with { Type = new NubArrayType(constArrayType.ElementType) };
}
// note(nub31): Implicit conversion of const array to slice
case NubSliceType when result.Type is NubConstArrayType constArrayType:
{
return new ConstArrayToSliceNode(result.Tokens, new NubSliceType(constArrayType.ElementType), result);
}
// note(nub31): Implicit conversion of int to larger int
case NubIntType expectedIntType when result.Type is NubIntType intType && expectedIntType.Width > intType.Width:
{
return new ConvertIntNode(result.Tokens, result, intType.Width, expectedIntType.Width, intType.Signed, expectedIntType.Signed);
}
// note(nub31): Implicit conversion of f32 to f64
case NubFloatType expectedFloatType when result.Type is NubFloatType floatType && expectedFloatType.Width > floatType.Width:
{
return new ConvertFloatNode(result.Tokens, result, floatType.Width, expectedFloatType.Width);
}
// note(nub31): Implicit conversion of cstring to string
case NubStringType when result.Type is NubCStringType:
{
return new ConvertCStringToStringNode(result.Tokens, result);
}
// note(nub31): No implicit conversion was possible or the result value was already the correct type
default:
{
return result;
}
}
}
// todo(nub31): Infer int type instead of explicit type syntax
@@ -368,18 +402,61 @@ public sealed class TypeChecker
return target.Type switch
{
NubArrayType arrayType => new ArrayIndexAccessNode(expression.Tokens, arrayType.ElementType, target, index),
NubConstArrayType constArrayType => new ConstArrayIndexAccessNode(expression.Tokens, constArrayType.ElementType, target, index),
NubSliceType sliceType => new SliceIndexAccessNode(expression.Tokens, sliceType.ElementType, target, index),
_ => throw new TypeCheckerException(Diagnostic.Error($"Cannot use array indexer on type {target.Type}").At(expression).Build())
};
}
// todo(nub31): Allow type inference instead of specifying type in syntax. Something like just []
private ArrayInitializerNode CheckArrayInitializer(ArrayInitializerSyntax expression, NubType? _)
private ExpressionNode CheckArrayInitializer(ArrayInitializerSyntax expression, NubType? expectedType)
{
var elementType = ResolveType(expression.ElementType);
var capacity = CheckExpression(expression.Capacity);
var type = new NubArrayType(elementType);
return new ArrayInitializerNode(expression.Tokens, type, capacity, elementType);
var elementType = expectedType switch
{
NubArrayType arrayType => arrayType.ElementType,
NubConstArrayType constArrayType => constArrayType.ElementType,
NubSliceType sliceType => sliceType.ElementType,
_ => null
};
if (elementType == null)
{
var firstValue = expression.Values.FirstOrDefault();
if (firstValue != null)
{
elementType = CheckExpression(firstValue).Type;
}
}
if (elementType == null)
{
throw new TypeCheckerException(Diagnostic
.Error("Unable to infer type of array initializer")
.At(expression)
.WithHelp("Provide a type for a variable assignment")
.Build());
}
var values = new List<ExpressionNode>();
foreach (var valueExpression in expression.Values)
{
var value = CheckExpression(valueExpression, elementType);
if (value.Type != elementType)
{
throw new TypeCheckerException(Diagnostic
.Error("Value in array initializer is not the same as the array type")
.At(valueExpression)
.Build());
}
values.Add(value);
}
return expectedType switch
{
NubArrayType => new ArrayInitializerNode(expression.Tokens, new NubArrayType(elementType), values),
NubConstArrayType constArrayType => new ConstArrayInitializerNode(expression.Tokens, constArrayType, values),
_ => new ConstArrayInitializerNode(expression.Tokens, new NubConstArrayType(elementType, expression.Values.Count), values)
};
}
private BinaryExpressionNode CheckBinaryExpression(BinaryExpressionSyntax expression, NubType? expectedType)