From 76efc849845bd512422fd990dc5d680f9f01ecfc Mon Sep 17 00:00:00 2001 From: nub31 Date: Mon, 23 Feb 2026 18:35:08 +0100 Subject: [PATCH] ... --- compiler/Generator.cs | 8 +++---- compiler/NubType.cs | 26 ----------------------- compiler/TypeChecker.cs | 46 +++++++++++++++++++++++++---------------- examples/build.sh | 2 ++ 4 files changed, 34 insertions(+), 48 deletions(-) diff --git a/compiler/Generator.cs b/compiler/Generator.cs index 61b4ef9..92c35dd 100644 --- a/compiler/Generator.cs +++ b/compiler/Generator.cs @@ -399,13 +399,13 @@ public class Generator private string EmitExpressionEnumLiteral(TypedNodeExpressionEnumLiteral expression) { - var enumType = (NubTypeEnumVariant)expression.Type; + var enumType = (NubTypeEnum)expression.Type; - if (!moduleGraph.TryResolveType(enumType.Module, enumType.EnumName, true, out var info)) + if (!moduleGraph.TryResolveType(enumType.Module, enumType.Name, true, out var info)) throw new UnreachableException(); var enumInfo = (Module.TypeInfoEnum)info; - var tag = enumInfo.Variants.ToList().FindIndex(x => x.Name == enumType.VariantName); + var tag = enumInfo.Variants.ToList().FindIndex(x => x.Name == expression.EnumVariant); var initializerValues = new Dictionary(); @@ -417,7 +417,7 @@ public class Generator var initializerStrings = initializerValues.Select(x => $".{x.Key} = {x.Value}"); - return $"({CType(expression.Type)}){{ .tag = {tag}, .{enumType.VariantName} = {{{string.Join(", ", initializerStrings)}}} }}"; + return $"({CType(expression.Type)}){{ .tag = {tag}, .{expression.EnumVariant} = {{ {string.Join(", ", initializerStrings)} }} }}"; } private string EmitExpressionMemberAccess(TypedNodeExpressionMemberAccess expression) diff --git a/compiler/NubType.cs b/compiler/NubType.cs index 4b63b9f..962868b 100644 --- a/compiler/NubType.cs +++ b/compiler/NubType.cs @@ -135,32 +135,6 @@ public class NubTypeEnum : NubType public override string ToString() => $"enum {Module}::{Name}"; } -public class NubTypeEnumVariant : NubType -{ - private static readonly Dictionary<(string Module, string EnumName, string VariantName), NubTypeEnumVariant> Cache = new(); - - public static NubTypeEnumVariant Get(string module, string enumName, string variantName) - { - if (!Cache.TryGetValue((module, enumName, variantName), out var enumType)) - Cache[(module, enumName, variantName)] = enumType = new NubTypeEnumVariant(module, enumName, variantName); - - return enumType; - } - - private NubTypeEnumVariant(string module, string enumName, string variantName) - { - Module = module; - EnumName = enumName; - VariantName = variantName; - } - - public string Module { get; } - public string EnumName { get; } - public string VariantName { get; } - - public override string ToString() => $"enum {Module}::{EnumName}.{VariantName}"; -} - public class NubTypePointer : NubType { private static readonly Dictionary Cache = new(); diff --git a/compiler/TypeChecker.cs b/compiler/TypeChecker.cs index f8d5e9f..75e94ca 100644 --- a/compiler/TypeChecker.cs +++ b/compiler/TypeChecker.cs @@ -47,7 +47,7 @@ public class TypeChecker continue; } - scope.DeclareIdentifier(parameter.Name.Ident, parameterType); + scope.DeclareIdentifier(parameter.Name.Ident, parameterType, null); parameters.Add(new TypedNodeDefinitionFunc.Param(parameter.Tokens, parameter.Name, parameterType)); } @@ -132,7 +132,7 @@ public class TypeChecker if (type != value.Type) throw new CompileException(Diagnostic.Error("Type of variable does match type of assigned value").At(fileName, value).Build()); - scope.DeclareIdentifier(statement.Name.Ident, type); + scope.DeclareIdentifier(statement.Name.Ident, type, value.EnumVariant); return new TypedNodeStatementVariableDeclaration(statement.Tokens, statement.Name, type, value); } @@ -152,7 +152,7 @@ public class TypeChecker { using (scope.EnterScope()) { - scope.DeclareIdentifier(@case.VariableName.Ident, NubTypeEnumVariant.Get(enumType.Module, enumType.Name, @case.Type.Ident)); + scope.DeclareIdentifier(@case.VariableName.Ident, NubTypeEnum.Get(enumType.Module, enumType.Name), @case.Type.Ident); var body = CheckStatement(@case.Body); cases.Add(new TypedNodeStatementMatch.Case(@case.Tokens, @case.Type, @case.VariableName, body)); } @@ -321,10 +321,13 @@ public class TypeChecker private TypedNodeExpressionLocalIdent CheckExpressionIdent(NodeExpressionLocalIdent expression) { var type = scope.GetIdentifierType(expression.Value.Ident); - if (type == null) + if (!type.HasValue) throw new CompileException(Diagnostic.Error($"Identifier '{expression.Value.Ident}' is not declared").At(fileName, expression.Value).Build()); - return new TypedNodeExpressionLocalIdent(expression.Tokens, type, expression.Value); + return new TypedNodeExpressionLocalIdent(expression.Tokens, type.Value.Type, expression.Value) + { + EnumVariant = type.Value.EnumVariant + }; } private TypedNodeExpressionModuleIdent CheckExpressionModuleIdent(NodeExpressionModuleIdent expression) @@ -368,20 +371,23 @@ public class TypeChecker return new TypedNodeExpressionMemberAccess(expression.Tokens, field.Type, target, expression.Name); } - case NubTypeEnumVariant enumVariantType: + case NubTypeEnum enumType: { - if (!moduleGraph.TryResolveModule(enumVariantType.Module, out var module)) - throw new CompileException(Diagnostic.Error($"Module '{enumVariantType.Module}' not found").At(fileName, expression.Target).Build()); + if (target.EnumVariant == null) + throw new CompileException(Diagnostic.Error($"Cannot access member '{expression.Name.Ident}' on enum '{enumType}' without knowing the variant").At(fileName, target).Build()); - if (!module.TryResolveType(enumVariantType.EnumName, moduleName == enumVariantType.Module, out var typeDef)) - throw new CompileException(Diagnostic.Error($"Type '{enumVariantType.EnumName}' not found in module '{enumVariantType.Module}'").At(fileName, expression.Target).Build()); + if (!moduleGraph.TryResolveModule(enumType.Module, out var module)) + throw new CompileException(Diagnostic.Error($"Module '{enumType.Module}' not found").At(fileName, expression.Target).Build()); + + if (!module.TryResolveType(enumType.Name, moduleName == enumType.Module, out var typeDef)) + throw new CompileException(Diagnostic.Error($"Type '{enumType.Name}' not found in module '{enumType.Module}'").At(fileName, expression.Target).Build()); if (typeDef is not Module.TypeInfoEnum enumDef) - throw new CompileException(Diagnostic.Error($"Type '{enumVariantType.Module}::{enumVariantType.EnumName}' is not an enum").At(fileName, expression.Target).Build()); + throw new CompileException(Diagnostic.Error($"Type '{enumType.Module}::{enumType.Name}' is not an enum").At(fileName, expression.Target).Build()); - var variant = enumDef.Variants.FirstOrDefault(x => x.Name == enumVariantType.VariantName); + var variant = enumDef.Variants.FirstOrDefault(x => x.Name == target.EnumVariant); if (variant == null) - throw new CompileException(Diagnostic.Error($"Type '{target.Type}' does not have a variant '{enumVariantType.VariantName}'").At(fileName, expression.Target).Build()); + throw new CompileException(Diagnostic.Error($"Type '{target.Type}' does not have a variant '{target.EnumVariant}'").At(fileName, expression.Target).Build()); var field = variant.Fields.FirstOrDefault(x => x.Name == expression.Name.Ident); if (field == null) @@ -471,7 +477,10 @@ public class TypeChecker initializers.Add(new TypedNodeExpressionEnumLiteral.Initializer(initializer.Tokens, initializer.Name, value)); } - return new TypedNodeExpressionEnumLiteral(expression.Tokens, NubTypeEnumVariant.Get(expression.Module.Ident, expression.EnumName.Ident, expression.VariantName.Ident), initializers); + return new TypedNodeExpressionEnumLiteral(expression.Tokens, NubTypeEnum.Get(expression.Module.Ident, expression.EnumName.Ident), initializers) + { + EnumVariant = expression.VariantName.Ident + }; } private NubType ResolveType(NodeType node) @@ -510,7 +519,7 @@ public class TypeChecker private sealed class Scope { - private readonly Stack> scopes = new(); + private readonly Stack> scopes = new(); public IDisposable EnterScope() { @@ -518,12 +527,12 @@ public class TypeChecker return new ScopeGuard(this); } - public void DeclareIdentifier(string name, NubType type) + public void DeclareIdentifier(string name, NubType type, string? enumVariant) { - scopes.Peek().Add(name, type); + scopes.Peek().Add(name, (type, enumVariant)); } - public NubType? GetIdentifierType(string name) + public (NubType Type, string? EnumVariant)? GetIdentifierType(string name) { foreach (var scope in scopes) { @@ -640,6 +649,7 @@ public class TypedNodeStatementMatch(List tokens, TypedNodeExpression tar public abstract class TypedNodeExpression(List tokens, NubType type) : TypedNode(tokens) { public NubType Type { get; } = type; + public string? EnumVariant { get; init; } } public class TypedNodeExpressionIntLiteral(List tokens, NubType type, TokenIntLiteral value) : TypedNodeExpression(tokens, type) diff --git a/examples/build.sh b/examples/build.sh index 60e3eea..8d6f5ab 100755 --- a/examples/build.sh +++ b/examples/build.sh @@ -1,3 +1,5 @@ +set -e + pushd math dotnet run --project ../../compiler math.nub --type=lib pushd .build