This commit is contained in:
nub31
2025-10-22 17:45:53 +02:00
parent c48f7c6244
commit 8e37852df0
9 changed files with 201 additions and 86 deletions

View File

@@ -80,6 +80,8 @@ public abstract record LValueExpressionNode(List<Token> Tokens, NubType Type) :
public abstract record RValueExpressionNode(List<Token> Tokens, NubType Type) : ExpressionNode(Tokens, Type);
public abstract record IntermediateExpression(List<Token> Tokens) : ExpressionNode(Tokens, new NubVoidType());
public record StringLiteralNode(List<Token> Tokens, string Value) : RValueExpressionNode(Tokens, new NubStringType());
public record CStringLiteralNode(List<Token> Tokens, string Value) : RValueExpressionNode(Tokens, new NubCStringType());
@@ -142,4 +144,6 @@ public record SizeBuiltinNode(List<Token> Tokens, NubType Type, NubType TargetTy
public record FloatToIntBuiltinNode(List<Token> Tokens, NubType Type, ExpressionNode Value, NubFloatType ValueType, NubIntType TargetType) : RValueExpressionNode(Tokens, Type);
public record EnumReferenceIntermediateNode(List<Token> Tokens, string Module, string Name) : IntermediateExpression(Tokens);
#endregion

View File

@@ -557,55 +557,56 @@ public sealed class TypeChecker
return new FuncCallNode(expression.Tokens, funcType.ReturnType, accessor, parameters);
}
private ExpressionNode CheckIdentifier(ExpressionSyntax expression, string moduleName, string name)
{
if (!_importedModules.TryGetValue(moduleName, out var module))
{
throw new TypeCheckerException(Diagnostic
.Error($"Module {moduleName} not found")
.WithHelp($"import \"{moduleName}\"")
.At(expression)
.Build());
}
var function = module.Functions(IsCurretModule(moduleName)).FirstOrDefault(x => x.Name == name);
if (function != null)
{
using (BeginRootScope(moduleName))
{
var parameters = function.Prototype.Parameters.Select(x => ResolveType(x.Type)).ToList();
var type = new NubFuncType(parameters, ResolveType(function.Prototype.ReturnType));
return new FuncIdentifierNode(expression.Tokens, type, moduleName, name, function.Prototype.ExternSymbol);
}
}
var enumDef = module.Enums(IsCurretModule(moduleName)).FirstOrDefault(x => x.Name == name);
if (enumDef != null)
{
return new EnumReferenceIntermediateNode(expression.Tokens, moduleName, name);
}
throw new TypeCheckerException(Diagnostic
.Error($"No exported symbol {name} not found in module {moduleName}")
.At(expression)
.Build());
}
private ExpressionNode CheckLocalIdentifier(LocalIdentifierSyntax expression, NubType? _)
{
// note(nub31): Local identifiers can be variables or a symbol in a module
var scopeIdent = Scope.LookupVariable(expression.Name);
if (scopeIdent != null)
{
return new VariableIdentifierNode(expression.Tokens, scopeIdent.Type, expression.Name);
}
var module = _importedModules[Scope.Module];
var function = module.Functions(true).FirstOrDefault(x => x.Name == expression.Name);
if (function != null)
{
var parameters = function.Prototype.Parameters.Select(x => ResolveType(x.Type)).ToList();
var type = new NubFuncType(parameters, ResolveType(function.Prototype.ReturnType));
return new FuncIdentifierNode(expression.Tokens, type, Scope.Module, expression.Name, function.Prototype.ExternSymbol);
}
throw new TypeCheckerException(Diagnostic.Error($"Symbol {expression.Name} not found").At(expression).Build());
return CheckIdentifier(expression, Scope.Module, expression.Name);
}
private ExpressionNode CheckModuleIdentifier(ModuleIdentifierSyntax expression, NubType? _)
{
if (!_importedModules.TryGetValue(expression.Module, out var module))
{
throw new TypeCheckerException(Diagnostic
.Error($"Module {expression.Module} not found")
.WithHelp($"import \"{expression.Module}\"")
.At(expression)
.Build());
}
var includePrivate = expression.Module == Scope.Module;
var function = module.Functions(includePrivate).FirstOrDefault(x => x.Name == expression.Name);
if (function != null)
{
using (BeginRootScope(expression.Module))
{
var parameters = function.Prototype.Parameters.Select(x => ResolveType(x.Type)).ToList();
var type = new NubFuncType(parameters, ResolveType(function.Prototype.ReturnType));
return new FuncIdentifierNode(expression.Tokens, type, expression.Module, expression.Name, function.Prototype.ExternSymbol);
}
}
throw new TypeCheckerException(Diagnostic
.Error($"No exported symbol {expression.Name} not found in module {expression.Module}")
.At(expression)
.Build());
// note(nub31): Unlike local identifiers, module identifiers does not look for local variables
return CheckIdentifier(expression, expression.Module, expression.Name);
}
private ExpressionNode CheckStringLiteral(StringLiteralSyntax expression, NubType? expectedType)
@@ -668,29 +669,56 @@ public sealed class TypeChecker
private ExpressionNode CheckMemberAccess(MemberAccessSyntax expression, NubType? _)
{
var target = CheckExpression(expression.Target);
switch (target.Type)
{
case NubStructType structType:
{
var field = structType.Fields.FirstOrDefault(x => x.Name == expression.Member);
if (field == null)
{
throw new TypeCheckerException(Diagnostic
.Error($"Struct {target.Type} does not have a field with the name {expression.Member}")
.At(expression)
.Build());
}
return new StructFieldAccessNode(expression.Tokens, field.Type, target, expression.Member);
}
default:
if (target is EnumReferenceIntermediateNode enumReferenceIntermediate)
{
var enumDef = _importedModules[enumReferenceIntermediate.Module]
.Enums(IsCurretModule(enumReferenceIntermediate.Module))
.First(x => x.Name == enumReferenceIntermediate.Name);
var field = enumDef.Fields.FirstOrDefault(x => x.Name == expression.Member);
if (field == null)
{
throw new TypeCheckerException(Diagnostic
.Error($"Cannot access struct member on non-struct type {target.Type}")
.Error($"Enum {Scope.Module}::{enumReferenceIntermediate.Name} does not have a field named {expression.Member}")
.At(enumDef)
.Build());
}
var enumType = enumDef.Type != null ? ResolveType(enumDef.Type) : new NubIntType(false, 64);
if (enumType is not NubIntType enumIntType)
{
throw new TypeCheckerException(Diagnostic.Error("Enum type must be an int type").At(enumDef.Type).Build());
}
return enumIntType.Width switch
{
8 => enumIntType.Signed ? new I8LiteralNode(expression.Tokens, (sbyte)field.Value) : new U8LiteralNode(expression.Tokens, (byte)field.Value),
16 => enumIntType.Signed ? new I16LiteralNode(expression.Tokens, (short)field.Value) : new U16LiteralNode(expression.Tokens, (ushort)field.Value),
32 => enumIntType.Signed ? new I32LiteralNode(expression.Tokens, (int)field.Value) : new U32LiteralNode(expression.Tokens, (uint)field.Value),
64 => enumIntType.Signed ? new I64LiteralNode(expression.Tokens, field.Value) : new U64LiteralNode(expression.Tokens, (ulong)field.Value),
_ => throw new ArgumentOutOfRangeException()
};
}
if (target.Type is NubStructType structType)
{
var field = structType.Fields.FirstOrDefault(x => x.Name == expression.Member);
if (field == null)
{
throw new TypeCheckerException(Diagnostic
.Error($"Struct {target.Type} does not have a field with the name {expression.Member}")
.At(expression)
.Build());
}
return new StructFieldAccessNode(expression.Tokens, field.Type, target, expression.Member);
}
throw new TypeCheckerException(Diagnostic
.Error($"Cannot access struct member {expression.Member} on type {target.Type}")
.At(expression)
.Build());
}
private StructInitializerNode CheckStructInitializer(StructInitializerSyntax expression, NubType? expectedType)
@@ -831,35 +859,39 @@ public sealed class TypeChecker
private NubType ResolveCustomType(CustomTypeSyntax customType)
{
var key = (customType.Module ?? Scope.Module, customType.Name);
if (_typeCache.TryGetValue(key, out var cachedType))
if (!_importedModules.TryGetValue(customType.Module ?? Scope.Module, out var module))
{
return cachedType;
throw new TypeCheckerException(Diagnostic
.Error($"Module {customType.Module ?? Scope.Module} not found")
.WithHelp($"import \"{customType.Module ?? Scope.Module}\"")
.At(customType)
.Build());
}
if (!_resolvingTypes.Add(key))
var enumDef = module.Enums(IsCurretModule(customType.Module)).FirstOrDefault(x => x.Name == customType.Name);
if (enumDef != null)
{
var placeholder = new NubStructType(customType.Module ?? Scope.Module, customType.Name, []);
_typeCache[key] = placeholder;
return placeholder;
return enumDef.Type != null ? ResolveType(enumDef.Type) : new NubIntType(false, 64);
}
try
var structDef = module.Structs(IsCurretModule(customType.Module)).FirstOrDefault(x => x.Name == customType.Name);
if (structDef != null)
{
if (!_importedModules.TryGetValue(customType.Module ?? Scope.Module, out var module))
var key = (customType.Module ?? Scope.Module, customType.Name);
if (_typeCache.TryGetValue(key, out var cachedType))
{
throw new TypeCheckerException(Diagnostic
.Error($"Module {customType.Module} not found")
.WithHelp($"import \"{customType.Module}\"")
.At(customType)
.Build());
return cachedType;
}
var includePrivate = customType.Module == Scope.Module;
if (!_resolvingTypes.Add(key))
{
var placeholder = new NubStructType(customType.Module ?? Scope.Module, customType.Name, []);
_typeCache[key] = placeholder;
return placeholder;
}
var structDef = module.Structs(includePrivate).FirstOrDefault(x => x.Name == customType.Name);
if (structDef != null)
try
{
var result = new NubStructType(customType.Module ?? Scope.Module, structDef.Name, []);
_typeCache[key] = result;
@@ -871,16 +903,26 @@ public sealed class TypeChecker
result.Fields.AddRange(fields);
return result;
}
finally
{
_resolvingTypes.Remove(key);
}
}
throw new TypeCheckerException(Diagnostic
.Error($"Type {customType.Name} not found in module {customType.Module}")
.At(customType)
.Build());
}
finally
throw new TypeCheckerException(Diagnostic
.Error($"Type {customType.Name} not found in module {customType.Module ?? Scope.Module}")
.At(customType)
.Build());
}
private bool IsCurretModule(string? module)
{
if (module == null)
{
_resolvingTypes.Remove(key);
return true;
}
return module == Scope.Module;
}
}