From d0c31ad17fd5ddc73f682f27eaca2df8325f1480 Mon Sep 17 00:00:00 2001 From: nub31 Date: Tue, 10 Feb 2026 20:51:28 +0100 Subject: [PATCH] global variables --- compiler/Generator.cs | 4 ++-- compiler/ModuleGraph.cs | 33 +++++++++++++++++++-------------- compiler/Parser.cs | 22 ++++++++++++++++++++++ compiler/test.nub | 7 ++++++- 4 files changed, 49 insertions(+), 17 deletions(-) diff --git a/compiler/Generator.cs b/compiler/Generator.cs index b383dc8..e2b097f 100644 --- a/compiler/Generator.cs +++ b/compiler/Generator.cs @@ -68,11 +68,11 @@ public sealed class Generator(List functions, ModuleGra if (!functions.Any(x => x.GetMangledName() == SymbolNameGen.Exported(module.Name, name, type))) writer.Write("extern "); - writer.WriteLine($"{CType(fn.ReturnType)} {SymbolNameGen.Exported(module.Name, name, type)}({string.Join(", ", fn.Parameters.Select(p => CType(p)))});"); + writer.WriteLine($"{CType(fn.ReturnType, SymbolNameGen.Exported(module.Name, name, type))}({string.Join(", ", fn.Parameters.Select(p => CType(p)))});"); } else { - writer.WriteLine($"{CType(type)} {SymbolNameGen.Exported(module.Name, name, type)};"); + writer.WriteLine($"{CType(type, SymbolNameGen.Exported(module.Name, name, type))};"); } } } diff --git a/compiler/ModuleGraph.cs b/compiler/ModuleGraph.cs index a10c279..7791036 100644 --- a/compiler/ModuleGraph.cs +++ b/compiler/ModuleGraph.cs @@ -116,8 +116,7 @@ public class ModuleGraph(Dictionary modules) // Second pass: Register struct types without fields foreach (var ast in asts) { - var module = astModuleCache.GetValueOrDefault(ast); - if (module == null) continue; + var module = astModuleCache[ast]; foreach (var structDef in ast.Definitions.OfType()) module.AddCustomType(structDef.Name.Ident, new NubTypeStruct(module.Name, structDef.Name.Ident, structDef.Packed), structDef.Exported); @@ -126,15 +125,14 @@ public class ModuleGraph(Dictionary modules) // Third pass: Resolve struct fields foreach (var ast in asts) { - var module = astModuleCache.GetValueOrDefault(ast); - if (module == null) continue; + var module = astModuleCache[ast]; foreach (var structDef in ast.Definitions.OfType()) { if (!module.TryResolveCustomType(structDef.Name.Ident, true, out var customType)) throw new UnreachableException($"{nameof(customType)} should always be registered"); - var fields = structDef.Fields.Select(f => new NubTypeStruct.Field(f.Name.Ident, ResolveType(f.Type, true))).ToList(); + var fields = structDef.Fields.Select(f => new NubTypeStruct.Field(f.Name.Ident, ResolveType(f.Type, module.Name))).ToList(); ((NubTypeStruct)customType).ResolveFields(fields); } } @@ -142,16 +140,21 @@ public class ModuleGraph(Dictionary modules) // Fourth pass: Register identifiers foreach (var ast in asts) { - var module = astModuleCache.GetValueOrDefault(ast); - if (module == null) continue; + var module = astModuleCache[ast]; foreach (var funcDef in ast.Definitions.OfType()) { - var parameters = funcDef.Parameters.Select(x => ResolveType(x.Type, true)).ToList(); - var returnType = ResolveType(funcDef.ReturnType, true); + var parameters = funcDef.Parameters.Select(x => ResolveType(x.Type, module.Name)).ToList(); + var returnType = ResolveType(funcDef.ReturnType, module.Name); var funcType = NubTypeFunc.Get(parameters, returnType); module.AddIdentifier(funcDef.Name.Ident, funcType, funcDef.Exported); } + + foreach (var globalVariable in ast.Definitions.OfType()) + { + var type = ResolveType(globalVariable.Type, module.Name); + module.AddIdentifier(globalVariable.Name.Ident, type, globalVariable.Exported); + } } if (diagnostics.Any(x => x.Severity == DiagnosticSeverity.Error)) @@ -159,14 +162,14 @@ public class ModuleGraph(Dictionary modules) return new ModuleGraph(modules); - NubType ResolveType(NodeType node, bool includePrivate) + NubType ResolveType(NodeType node, string currentModule) { return node switch { NodeTypeBool => NubTypeBool.Instance, - NodeTypeCustom type => ResolveCustomType(type, includePrivate), - NodeTypeFunc type => NubTypeFunc.Get(type.Parameters.Select(x => ResolveType(x, includePrivate)).ToList(), ResolveType(type.ReturnType, includePrivate)), - NodeTypePointer type => NubTypePointer.Get(ResolveType(type.To, includePrivate)), + NodeTypeCustom type => ResolveCustomType(type, currentModule), + NodeTypeFunc type => NubTypeFunc.Get(type.Parameters.Select(x => ResolveType(x, currentModule)).ToList(), ResolveType(type.ReturnType, currentModule)), + NodeTypePointer type => NubTypePointer.Get(ResolveType(type.To, currentModule)), NodeTypeSInt type => NubTypeSInt.Get(type.Width), NodeTypeUInt type => NubTypeUInt.Get(type.Width), NodeTypeString => NubTypeString.Instance, @@ -175,12 +178,14 @@ public class ModuleGraph(Dictionary modules) }; } - NubType ResolveCustomType(NodeTypeCustom type, bool includePrivate) + NubType ResolveCustomType(NodeTypeCustom type, string currentModule) { var module = modules.GetValueOrDefault(type.Module.Ident); if (module == null) throw new CompileException(Diagnostic.Error($"Unknown module: {type.Module.Ident}").Build()); + var includePrivate = currentModule == type.Module.Ident; + if (!module.TryResolveCustomType(type.Name.Ident, includePrivate, out var customType)) throw new CompileException(Diagnostic.Error($"Unknown custom type: {type.Module.Ident}::{type.Name.Ident}").Build()); diff --git a/compiler/Parser.cs b/compiler/Parser.cs index f4ab0b3..2f32b1a 100644 --- a/compiler/Parser.cs +++ b/compiler/Parser.cs @@ -121,6 +121,21 @@ public sealed class Parser(string fileName, List tokens) return new NodeDefinitionStruct(TokensFrom(startIndex), exported, packed, name, fields); } + if (TryExpectKeyword(Keyword.Let)) + { + var exported = modifiers.Remove(Keyword.Export); + + foreach (var modifier in modifiers) + // todo(nub31): Add to diagnostics instead of throwing + throw new CompileException(Diagnostic.Error("Invalid modifier for global variable").At(fileName, modifier.Value).Build()); + + var name = ExpectIdent(); + ExpectSymbol(Symbol.Colon); + var type = ParseType(); + + return new NodeDefinitionGlobalVariable(TokensFrom(startIndex), exported, name, type); + } + throw new CompileException(Diagnostic.Error("Not a valid definition").At(fileName, Peek()).Build()); } @@ -622,6 +637,13 @@ public sealed class NodeDefinitionStruct(List tokens, bool exported, bool } } +public sealed class NodeDefinitionGlobalVariable(List tokens, bool exported, TokenIdent name, NodeType type) : NodeDefinition(tokens) +{ + public bool Exported { get; } = exported; + public TokenIdent Name { get; } = name; + public NodeType Type { get; } = type; +} + public abstract class NodeStatement(List tokens) : Node(tokens); public sealed class NodeStatementBlock(List tokens, List statements) : NodeStatement(tokens) diff --git a/compiler/test.nub b/compiler/test.nub index 0f6cd4c..f158489 100644 --- a/compiler/test.nub +++ b/compiler/test.nub @@ -1,5 +1,7 @@ module main +let global: i32 + func main(): i32 { let x: i32 = 23 x = 24 @@ -23,5 +25,8 @@ func main(): i32 { x = test::do_something(me.name) test::do_something(me.name) - return x + + main::global = 123 + + return main::global } \ No newline at end of file