From 49734544e66f3d3ce195ed95b14f3e732b1117b7 Mon Sep 17 00:00:00 2001 From: nub31 Date: Wed, 25 Feb 2026 21:51:32 +0100 Subject: [PATCH] ... --- compiler/Generator.cs | 23 ++------------ compiler/ModuleGraph.cs | 14 +++------ compiler/NubLib.cs | 7 ++--- compiler/Parser.cs | 66 ++++++++--------------------------------- compiler/TypeChecker.cs | 55 +++++++++++----------------------- examples/math/math.nub | 35 +++++++--------------- 6 files changed, 50 insertions(+), 150 deletions(-) diff --git a/compiler/Generator.cs b/compiler/Generator.cs index 0324b56..bee57dd 100644 --- a/compiler/Generator.cs +++ b/compiler/Generator.cs @@ -96,16 +96,7 @@ public class Generator { foreach (var variant in e.Variants) { - writer.WriteLine("struct"); - writer.WriteLine("{"); - using (writer.Indent()) - { - foreach (var field in variant.Fields) - { - writer.WriteLine($"{CType(field.Type, field.Name)};"); - } - } - writer.WriteLine($"}} {variant.Name};"); + writer.WriteLine($"{CType(variant.Type, variant.Name)};"); } } writer.WriteLine("};"); @@ -407,17 +398,9 @@ public class Generator var enumInfo = (Module.TypeInfoEnum)info; var tag = enumInfo.Variants.ToList().FindIndex(x => x.Name == enumVariantType.Variant); - var initializerValues = new Dictionary(); + var value = EmitExpression(expression.Value); - foreach (var initializer in expression.Initializers) - { - var values = EmitExpression(initializer.Value); - initializerValues[initializer.Name.Ident] = values; - } - - var initializerStrings = initializerValues.Select(x => $".{x.Key} = {x.Value}"); - - return $"({CType(expression.Type)}){{ .tag = {tag}, .{enumVariantType.Variant} = {{ {string.Join(", ", initializerStrings)} }} }}"; + return $"({CType(expression.Type)}){{ .tag = {tag}, .{enumVariantType.Variant} = {value} }}"; } private string EmitExpressionMemberAccess(TypedNodeExpressionMemberAccess expression) diff --git a/compiler/ModuleGraph.cs b/compiler/ModuleGraph.cs index 7cbc095..61460c1 100644 --- a/compiler/ModuleGraph.cs +++ b/compiler/ModuleGraph.cs @@ -95,7 +95,7 @@ public class ModuleGraph case Manifest.Module.TypeInfoEnum s: { var info = new Module.TypeInfoEnum(Module.DefinitionKind.External); - var variants = s.Variants.Select(v => new Module.TypeInfoEnum.Variant(v.Name, v.Fields.Select(x => new Module.TypeInfoEnum.Variant.Field(x.Name, x.Type)).ToList())).ToList(); + var variants = s.Variants.Select(v => new Module.TypeInfoEnum.Variant(v.Name, v.Type)).ToList(); info.SetVariants(variants); module.AddType(name, info); break; @@ -152,7 +152,7 @@ public class ModuleGraph if (typeInfo is Module.TypeInfoEnum enumType) { - var variants = enumDef.Variants.Select(v => new Module.TypeInfoEnum.Variant(v.Name.Ident, v.Fields.Select(f => new Module.TypeInfoEnum.Variant.Field(f.Name.Ident, ResolveType(f.Type, module.Name))).ToList())).ToList(); + var variants = enumDef.Variants.Select(v => new Module.TypeInfoEnum.Variant(v.Name.Ident, ResolveType(v.Type, module.Name))).ToList(); enumType.SetVariants(variants); } } @@ -421,16 +421,10 @@ public class Module(string name) this.variants = variants; } - public class Variant(string name, List fields) + public class Variant(string name, NubType type) { public string Name { get; } = name; - public List Fields { get; } = fields; - - public class Field(string name, NubType type) - { - public string Name { get; } = name; - public NubType Type { get; } = type; - } + public NubType Type { get; } = type; } } } \ No newline at end of file diff --git a/compiler/NubLib.cs b/compiler/NubLib.cs index 705067b..599c62f 100644 --- a/compiler/NubLib.cs +++ b/compiler/NubLib.cs @@ -99,7 +99,7 @@ public record Manifest(Dictionary Modules) return typeInfo switch { Compiler.Module.TypeInfoStruct s => new Module.TypeInfoStruct(s.Packed, s.Fields.Select(x => new Module.TypeInfoStruct.Field(x.Name, x.Type)).ToList()), - Compiler.Module.TypeInfoEnum e => new Module.TypeInfoEnum(e.Variants.Select(v => new Module.TypeInfoEnum.Variant(v.Name, v.Fields.Select(x => new Module.TypeInfoEnum.Variant.Field(x.Name, x.Type)).ToList())).ToList()), + Compiler.Module.TypeInfoEnum e => new Module.TypeInfoEnum(e.Variants.Select(v => new Module.TypeInfoEnum.Variant(v.Name, v.Type)).ToList()), _ => throw new ArgumentOutOfRangeException(nameof(typeInfo)) }; } @@ -121,10 +121,7 @@ public record Manifest(Dictionary Modules) public record TypeInfoEnum(IReadOnlyList Variants) : TypeInfo { - public record Variant(string Name, List Fields) - { - public record Field(string Name, NubType Type); - } + public record Variant(string Name, NubType Type); } } } \ No newline at end of file diff --git a/compiler/Parser.cs b/compiler/Parser.cs index 4b1b1e2..0297470 100644 --- a/compiler/Parser.cs +++ b/compiler/Parser.cs @@ -145,24 +145,9 @@ public class Parser { var variantsStartIndex = index; var variantName = ExpectIdent(); - - var variantFields = new List(); - - if (TryExpectSymbol(Symbol.OpenCurly)) - { - while (!TryExpectSymbol(Symbol.CloseCurly)) - { - var fieldStartIndex = index; - - var fieldName = ExpectIdent(); - ExpectSymbol(Symbol.Colon); - var fieldType = ParseType(); - - variantFields.Add(new NodeDefinitionEnum.Variant.Field(TokensFrom(fieldStartIndex), fieldName, fieldType)); - } - } - - variants.Add(new NodeDefinitionEnum.Variant(TokensFrom(variantsStartIndex), variantName, variantFields)); + ExpectSymbol(Symbol.Colon); + var variantType = ParseType(); + variants.Add(new NodeDefinitionEnum.Variant(TokensFrom(variantsStartIndex), variantName, variantType)); } return new NodeDefinitionEnum(TokensFrom(startIndex), exported, name, variants); @@ -361,9 +346,7 @@ public class Parser } else if (TryExpectKeyword(Keyword.Struct)) { - var module = ExpectIdent(); - ExpectSymbol(Symbol.ColonColon); - var name = ExpectIdent(); + var type = ParseType(); var initializers = new List(); @@ -377,7 +360,7 @@ public class Parser initializers.Add(new NodeExpressionStructLiteral.Initializer(TokensFrom(initializerStartIndex), fieldName, fieldValue)); } - expr = new NodeExpressionStructLiteral(TokensFrom(startIndex), module, name, initializers); + expr = new NodeExpressionStructLiteral(TokensFrom(startIndex), type, initializers); } else if (TryExpectKeyword(Keyword.Enum)) { @@ -387,19 +370,9 @@ public class Parser ExpectSymbol(Symbol.ColonColon); var variantName = ExpectIdent(); - var initializers = new List(); + var value = ParseExpression(); - ExpectSymbol(Symbol.OpenCurly); - while (!TryExpectSymbol(Symbol.CloseCurly)) - { - var initializerStartIndex = startIndex; - var fieldName = ExpectIdent(); - ExpectSymbol(Symbol.Equal); - var fieldValue = ParseExpression(); - initializers.Add(new NodeExpressionEnumLiteral.Initializer(TokensFrom(initializerStartIndex), fieldName, fieldValue)); - } - - expr = new NodeExpressionEnumLiteral(TokensFrom(startIndex), module, enumName, variantName, initializers); + expr = new NodeExpressionEnumLiteral(TokensFrom(startIndex), module, enumName, variantName, value); } else { @@ -757,16 +730,10 @@ public class NodeDefinitionEnum(List tokens, bool exported, TokenIdent na public TokenIdent Name { get; } = name; public List Variants { get; } = variants; - public class Variant(List tokens, TokenIdent name, List fields) : Node(tokens) + public class Variant(List tokens, TokenIdent name, NodeType type) : Node(tokens) { public TokenIdent Name { get; } = name; - public List Fields { get; } = fields; - - public class Field(List tokens, TokenIdent name, NodeType type) : Node(tokens) - { - public TokenIdent Name { get; } = name; - public NodeType Type { get; } = type; - } + public NodeType Type { get; } = type; } } @@ -850,10 +817,9 @@ public class NodeExpressionBoolLiteral(List tokens, TokenBoolLiteral valu public TokenBoolLiteral Value { get; } = value; } -public class NodeExpressionStructLiteral(List tokens, TokenIdent module, TokenIdent name, List initializers) : NodeExpression(tokens) +public class NodeExpressionStructLiteral(List tokens, NodeType? type, List initializers) : NodeExpression(tokens) { - public TokenIdent Module { get; } = module; - public TokenIdent Name { get; } = name; + public NodeType? Type { get; } = type; public List Initializers { get; } = initializers; public class Initializer(List tokens, TokenIdent name, NodeExpression value) : Node(tokens) @@ -863,18 +829,12 @@ public class NodeExpressionStructLiteral(List tokens, TokenIdent module, } } -public class NodeExpressionEnumLiteral(List tokens, TokenIdent module, TokenIdent enumName, TokenIdent variantName, List initializers) : NodeExpression(tokens) +public class NodeExpressionEnumLiteral(List tokens, TokenIdent module, TokenIdent enumName, TokenIdent variantName, NodeExpression value) : NodeExpression(tokens) { public TokenIdent Module { get; } = module; public TokenIdent EnumName { get; } = enumName; public TokenIdent VariantName { get; } = variantName; - public List Initializers { get; } = initializers; - - public class Initializer(List tokens, TokenIdent name, NodeExpression value) : Node(tokens) - { - public TokenIdent Name { get; } = name; - public NodeExpression Value { get; } = value; - } + public NodeExpression Value { get; } = value; } public class NodeExpressionMemberAccess(List tokens, NodeExpression target, TokenIdent name) : NodeExpression(tokens) diff --git a/compiler/TypeChecker.cs b/compiler/TypeChecker.cs index 61e562e..fc5697e 100644 --- a/compiler/TypeChecker.cs +++ b/compiler/TypeChecker.cs @@ -380,11 +380,7 @@ public class TypeChecker if (variant == null) throw BasicError($"Type '{target.Type}' does not have a variant named '{enumVariantType.Variant}'", expression.Target); - var field = variant.Fields.FirstOrDefault(x => x.Name == expression.Name.Ident); - if (field == null) - throw BasicError($"Enum variant '{target.Type}' does not have a field matching the name '{expression.Name.Ident}'", target); - - return new TypedNodeExpressionMemberAccess(expression.Tokens, field.Type, target, expression.Name); + return new TypedNodeExpressionMemberAccess(expression.Tokens, variant.Type, target, expression.Name); } default: throw BasicError($"{target.Type} has no member '{expression.Name.Ident}'", target); @@ -409,14 +405,22 @@ public class TypeChecker private TypedNodeExpressionStructLiteral CheckExpressionStructLiteral(NodeExpressionStructLiteral expression) { - var info = ResolveModuleStruct(ResolveModule(expression.Module), expression.Name); + var type = ResolveType(expression.Type); + if (type is not NubTypeStruct structType) + throw BasicError("Type of struct literal is not a struct", expression.Type); + + if (!moduleGraph.TryResolveType(structType.Module, structType.Name, structType.Module == currentModule, out var info)) + throw BasicError($"Type '{structType}' struct literal not found", expression.Type); + + if (info is not Module.TypeInfoStruct structInfo) + throw BasicError($"Type '{structType}' is not a struct", expression.Type); var initializers = new List(); foreach (var initializer in expression.Initializers) { - var field = info.Fields.FirstOrDefault(x => x.Name == initializer.Name.Ident); + 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 '{expression.Module.Ident}::{expression.Name.Ident}'", initializer.Name); + throw BasicError($"Field '{initializer.Name.Ident}' does not exist on struct '{structType.Module}::{structType.Name}'", initializer.Name); var value = CheckExpression(initializer.Value); if (!value.Type.IsAssignableTo(field.Type)) @@ -425,32 +429,13 @@ public class TypeChecker initializers.Add(new TypedNodeExpressionStructLiteral.Initializer(initializer.Tokens, initializer.Name, value)); } - return new TypedNodeExpressionStructLiteral(expression.Tokens, NubTypeStruct.Get(expression.Module.Ident, expression.Name.Ident), initializers); + return new TypedNodeExpressionStructLiteral(expression.Tokens, NubTypeStruct.Get(structType.Module, structType.Name), initializers); } private TypedNodeExpressionEnumLiteral CheckExpressionEnumLiteral(NodeExpressionEnumLiteral expression) { - var info = ResolveModuleEnum(ResolveModule(expression.Module), expression.EnumName); - - var variant = info.Variants.FirstOrDefault(x => x.Name == expression.VariantName.Ident); - if (variant == null) - throw BasicError($"Enum '{expression.Module.Ident}::{expression.EnumName.Ident}' does not have a variant '{expression.VariantName.Ident}'", expression.VariantName); - - var initializers = new List(); - foreach (var initializer in expression.Initializers) - { - var field = variant.Fields.FirstOrDefault(x => x.Name == initializer.Name.Ident); - if (field == null) - throw BasicError($"Field '{initializer.Name.Ident}' does not exist on enum variant '{expression.Module.Ident}::{expression.EnumName.Ident}.{expression.VariantName.Ident}'", initializer.Name); - - var value = CheckExpression(initializer.Value); - 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 TypedNodeExpressionEnumLiteral.Initializer(initializer.Tokens, initializer.Name, value)); - } - - return new TypedNodeExpressionEnumLiteral(expression.Tokens, NubTypeEnumVariant.Get(NubTypeEnum.Get(expression.Module.Ident, expression.EnumName.Ident), expression.VariantName.Ident), initializers); + var value = CheckExpression(expression.Value); + return new TypedNodeExpressionEnumLiteral(expression.Tokens, NubTypeEnumVariant.Get(NubTypeEnum.Get(expression.Module.Ident, expression.EnumName.Ident), expression.VariantName.Ident), value); } private NubType ResolveType(NodeType node) @@ -756,15 +741,9 @@ public class TypedNodeExpressionStructLiteral(List tokens, NubType type, } } -public class TypedNodeExpressionEnumLiteral(List tokens, NubType type, List initializers) : TypedNodeExpression(tokens, type) +public class TypedNodeExpressionEnumLiteral(List tokens, NubType type, TypedNodeExpression value) : TypedNodeExpression(tokens, type) { - public List Initializers { get; } = initializers; - - public class Initializer(List tokens, TokenIdent name, TypedNodeExpression value) : Node(tokens) - { - public TokenIdent Name { get; } = name; - public TypedNodeExpression Value { get; } = value; - } + public TypedNodeExpression Value { get; } = value; } public class TypedNodeExpressionMemberAccess(List tokens, NubType type, TypedNodeExpression target, TokenIdent name) : TypedNodeExpression(tokens, type) diff --git a/examples/math/math.nub b/examples/math/math.nub index de9fe25..e6f1dd2 100644 --- a/examples/math/math.nub +++ b/examples/math/math.nub @@ -1,55 +1,42 @@ module math -struct vec2 { +export struct vec2 { x: i32 y: i32 } -struct vec3 { +export struct vec3 { x: i32 y: i32 z: i32 } -struct color { +export struct color { r: i32 g: i32 b: i32 a: i32 } -struct example { - a: { - a: i32 - } - b: { - b: { - c: i32 - } - c: { - d: i32 - } - } +export struct example { + b: color } - export enum message { - quit - move { - x: i32 - y: i32 - } + quit: {} + move: color } export func add(a: i32 b: i32): i32 { - let message: message = enum math::message::move { x = 1 y = 1 } + let message: message = enum math::message::move struct color { r = 23 g = 46 b = 56 } match message { quit q {} move m { - m.x = 23 - m.y = 23 + m.r = 23 + m.g = 23 + m.b = 23 } }