This commit is contained in:
nub31
2026-03-01 18:14:54 +01:00
parent 5f4a4172bf
commit 2b7eb56895
9 changed files with 192 additions and 138 deletions

View File

@@ -208,15 +208,24 @@ public class TypeChecker
var cases = new List<TypedNodeStatementMatch.Case>();
foreach (var @case in statement.Cases)
{
if (!enumInfo.Variants.Any(x => x.Name == @case.Variant.Ident))
var variant = enumInfo.Variants.FirstOrDefault(x => x.Name == @case.Variant.Ident);
if (variant == null)
throw BasicError($"Enum type'{enumType}' does not have a variant named '{@case.Variant.Ident}'", @case.Variant);
uncoveredCases.Remove(@case.Variant.Ident);
using (scope.EnterScope())
{
scope.DeclareIdentifier(@case.VariableName.Ident, NubTypeEnumVariant.Get(NubTypeEnum.Get(enumType.Module, enumType.Name), @case.Variant.Ident));
if (@case.VariableName != null)
{
if (variant.Type is null)
throw BasicError("Cannot capture variable for enum variant without type", @case.VariableName);
scope.DeclareIdentifier(@case.VariableName.Ident, variant.Type);
}
var body = CheckStatement(@case.Body);
cases.Add(new TypedNodeStatementMatch.Case(@case.Tokens, @case.Variant, @case.VariableName, body));
}
}
@@ -240,7 +249,7 @@ public class TypeChecker
NodeExpressionFuncCall expression => CheckExpressionFuncCall(expression, expectedType),
NodeExpressionStringLiteral expression => CheckExpressionStringLiteral(expression, expectedType),
NodeExpressionStructLiteral expression => CheckExpressionStructLiteral(expression, expectedType),
NodeExpressionEnumLiteral expression => CheckExpressionEnumLiteral(expression, expectedType),
NodeExpressionNewNamedType expression => CheckExpressionNewNamedType(expression, expectedType),
_ => throw new ArgumentOutOfRangeException(nameof(node))
};
}
@@ -517,35 +526,7 @@ public class TypeChecker
private TypedNodeExpressionStructLiteral CheckExpressionStructLiteral(NodeExpressionStructLiteral expression, NubType? expectedType)
{
if (expression.Type != null)
{
var type = ResolveType(expression.Type);
if (type is not NubTypeStruct structType)
throw BasicError("Type of struct literal is not a struct", expression);
if (!moduleGraph.TryResolveType(structType.Module, structType.Name, structType.Module == currentModule, out var info))
throw BasicError($"Type '{structType}' struct literal not found", expression);
if (info is not Module.TypeInfoStruct structInfo)
throw BasicError($"Type '{structType}' is not a struct", expression.Type);
var initializers = new List<TypedNodeExpressionStructLiteral.Initializer>();
foreach (var initializer in expression.Initializers)
{
var field = structInfo.Fields.FirstOrDefault(x => x.Name == initializer.Name.Ident);
if (field == null)
throw BasicError($"Field '{initializer.Name.Ident}' does not exist on struct '{structType.Module}::{structType.Name}'", initializer.Name);
var value = CheckExpression(initializer.Value, field.Type);
if (!value.Type.IsAssignableTo(field.Type))
throw BasicError($"Type of assignment ({value.Type}) does not match expected type of field '{field.Name}' ({field.Type})", initializer.Name);
initializers.Add(new TypedNodeExpressionStructLiteral.Initializer(initializer.Tokens, initializer.Name, value));
}
return new TypedNodeExpressionStructLiteral(expression.Tokens, structType, initializers);
}
else if (expectedType is NubTypeStruct structType)
if (expectedType is NubTypeStruct structType)
{
if (!moduleGraph.TryResolveType(structType.Module, structType.Name, structType.Module == currentModule, out var info))
throw BasicError($"Type '{structType}' struct literal not found", expression);
@@ -602,24 +583,36 @@ public class TypeChecker
}
}
private TypedNodeExpressionEnumLiteral CheckExpressionEnumLiteral(NodeExpressionEnumLiteral expression, NubType? expectedType)
private TypedNodeExpressionNewNamedType CheckExpressionNewNamedType(NodeExpressionNewNamedType expression, NubType? expectedType)
{
var type = ResolveType(expression.Type);
if (type is not NubTypeEnumVariant variantType)
throw BasicError("Expected enum variant type", expression.Type);
switch (type)
{
case NubTypeStruct structType:
{
var value = CheckExpression(expression.Value, structType);
return new TypedNodeExpressionNewNamedType(expression.Tokens, structType, value);
}
case NubTypeEnumVariant enumVariantType:
{
if (!moduleGraph.TryResolveType(enumVariantType.EnumType.Module, enumVariantType.EnumType.Name, enumVariantType.EnumType.Module == currentModule, out var info))
throw BasicError($"Type '{enumVariantType.EnumType}' not found", expression.Type);
if (!moduleGraph.TryResolveType(variantType.EnumType.Module, variantType.EnumType.Name, variantType.EnumType.Module == currentModule, out var info))
throw BasicError($"Type '{variantType.EnumType}' not found", expression.Type);
if (info is not Module.TypeInfoEnum enumInfo)
throw BasicError($"Type '{enumVariantType.EnumType}' is not an enum", expression.Type);
if (info is not Module.TypeInfoEnum enumInfo)
throw BasicError($"Type '{variantType.EnumType}' is not an enum", expression.Type);
var variant = enumInfo.Variants.FirstOrDefault(x => x.Name == enumVariantType.Variant);
if (variant == null)
throw BasicError($"Enum type '{enumVariantType.EnumType}' does not have a variant named '{enumVariantType.Variant}'", expression.Type);
var variant = enumInfo.Variants.FirstOrDefault(x => x.Name == variantType.Variant);
if (variant == null)
throw BasicError($"Enum '{variantType.EnumType}' does not have a variant named '{variantType.Variant}'", expression.Type);
var value = CheckExpression(expression.Value, variant.Type);
return new TypedNodeExpressionEnumLiteral(expression.Tokens, type, value);
var value = CheckExpression(expression.Value, variant.Type);
return new TypedNodeExpressionNewNamedType(expression.Tokens, enumVariantType, value);
}
default:
{
throw BasicError($"'{type}' is not a valid type for the new operator", expression);
}
}
}
private NubType ResolveType(NodeType node)
@@ -860,10 +853,10 @@ public class TypedNodeStatementMatch(List<Token> tokens, TypedNodeExpression tar
public TypedNodeExpression Target { get; } = target;
public List<Case> Cases { get; } = cases;
public class Case(List<Token> tokens, TokenIdent type, TokenIdent variableName, TypedNodeStatement body) : Node(tokens)
public class Case(List<Token> tokens, TokenIdent type, TokenIdent? variableName, TypedNodeStatement body) : Node(tokens)
{
public TokenIdent Variant { get; } = type;
public TokenIdent VariableName { get; } = variableName;
public TokenIdent? VariableName { get; } = variableName;
public TypedNodeStatement Body { get; } = body;
}
}
@@ -899,7 +892,7 @@ public class TypedNodeExpressionStructLiteral(List<Token> tokens, NubType type,
}
}
public class TypedNodeExpressionEnumLiteral(List<Token> tokens, NubType type, TypedNodeExpression value) : TypedNodeExpression(tokens, type)
public class TypedNodeExpressionNewNamedType(List<Token> tokens, NubType type, TypedNodeExpression value) : TypedNodeExpression(tokens, type)
{
public TypedNodeExpression Value { get; } = value;
}