This commit is contained in:
nub31
2026-02-09 21:09:42 +01:00
parent ab9bd6fd05
commit ea3d374831
3 changed files with 75 additions and 69 deletions

View File

@@ -1,38 +1,21 @@
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
namespace Compiler;
public class ModuleGraph(Dictionary<string, ModuleGraph.Module> modules)
{
public static Builder Create() => new();
public NubTypeStruct ResolveStruct(string moduleName, string name)
public List<Module> GetModules()
{
var module = modules.GetValueOrDefault(moduleName);
if (module == null)
throw new CompileException(Diagnostic.Error($"Module '{moduleName}' not found").Build());
var structType = module.ResolveStruct(name);
if (structType == null)
throw new CompileException(Diagnostic.Error($"Struct '{moduleName}::{name}' not found").Build());
return structType;
return modules.Values.ToList();
}
public NubType ResolveIdentifier(string moduleName, string name)
public bool TryResolveModule(string moduleName, [NotNullWhen(true)] out Module? module)
{
var module = modules.GetValueOrDefault(moduleName);
if (module == null)
throw new CompileException(Diagnostic.Error($"Module '{moduleName}' not found").Build());
var identType = module.ResolveIdentifier(name);
if (identType == null)
throw new CompileException(Diagnostic.Error($"Function '{moduleName}::{name}' not found").Build());
return identType;
}
public List<NubTypeStruct> GetStructTypes()
{
return modules.SelectMany(x => x.Value.GetStructTypes()).ToList();
module = modules.GetValueOrDefault(moduleName);
return module != null;
}
public sealed class Module
@@ -45,19 +28,16 @@ public class ModuleGraph(Dictionary<string, ModuleGraph.Module> modules)
return structTypes.Values.ToList();
}
public List<NubType> GetIdentifiers()
public bool TryResolveStructType(string structName, [NotNullWhen(true)] out NubTypeStruct? structType)
{
return identifierTypes.Values.ToList();
structType = structTypes.GetValueOrDefault(structName);
return structType != null;
}
public NubTypeStruct? ResolveStruct(string name)
public bool TryResolveIdentifierType(string identifierName, [NotNullWhen(true)] out NubType? identifier)
{
return structTypes.GetValueOrDefault(name);
}
public NubType? ResolveIdentifier(string name)
{
return identifierTypes.GetValueOrDefault(name);
identifier = identifierTypes.GetValueOrDefault(identifierName);
return identifier != null;
}
public void AddStruct(string name, NubTypeStruct structType)
@@ -84,45 +64,54 @@ public class ModuleGraph(Dictionary<string, ModuleGraph.Module> modules)
{
diagnostics = [];
var astModuleCache = new Dictionary<Ast, Module>();
var modules = new Dictionary<string, Module>();
// First pass: Register modules
foreach (var ast in asts)
{
var moduleDefinitions = ast.Definitions.OfType<NodeDefinitionModule>().ToList();
var currentModule = moduleDefinitions[0].Name.Ident;
if (!modules.ContainsKey(currentModule))
modules.Add(currentModule, new Module());
if (moduleDefinitions.Count == 0)
diagnostics.Add(Diagnostic.Error("Missing module declaration").At(ast.FileName, 1, 1, 1).Build());
foreach (var extraModuleDefinition in moduleDefinitions.Skip(1))
diagnostics.Add(Diagnostic.Warning("Duplicate module declaration will be ignored").At(ast.FileName, extraModuleDefinition).Build());
if (moduleDefinitions.Count >= 1)
{
var currentModule = moduleDefinitions[0].Name.Ident;
if (!modules.ContainsKey(currentModule))
{
var module = new Module();
modules.Add(currentModule, module);
astModuleCache[ast] = module;
}
}
}
// Second pass: Register struct types without fields
foreach (var ast in asts)
{
var moduleDefinitions = ast.Definitions.OfType<NodeDefinitionModule>().ToList();
var currentModule = moduleDefinitions[0].Name.Ident;
if (!modules.TryGetValue(currentModule, out var module))
{
module = new Module();
modules[currentModule] = module;
}
var module = astModuleCache.GetValueOrDefault(ast);
if (module == null) continue;
foreach (var structDef in ast.Definitions.OfType<NodeDefinitionStruct>())
{
module.AddStruct(structDef.Name.Ident, new NubTypeStruct());
}
}
// Third pass: Resolve struct fields
foreach (var ast in asts)
{
var moduleDefinitions = ast.Definitions.OfType<NodeDefinitionModule>().ToList();
var module = modules[moduleDefinitions[0].Name.Ident];
var module = astModuleCache.GetValueOrDefault(ast);
if (module == null) continue;
foreach (var structDef in ast.Definitions.OfType<NodeDefinitionStruct>())
{
var structType = module.ResolveStruct(structDef.Name.Ident);
if (!module.TryResolveStructType(structDef.Name.Ident, out var structType))
throw new UnreachableException($"{nameof(structType)} should always be registered");
var fields = structDef.Fields.Select(f => new NubTypeStruct.Field(f.Name.Ident, Resolve(f.Type))).ToList();
structType.ResolveFields(fields);
}
@@ -131,8 +120,8 @@ public class ModuleGraph(Dictionary<string, ModuleGraph.Module> modules)
// Fourth pass: Register identifiers
foreach (var ast in asts)
{
var moduleDefinitions = ast.Definitions.OfType<NodeDefinitionModule>().ToList();
var module = modules[moduleDefinitions[0].Name.Ident];
var module = astModuleCache.GetValueOrDefault(ast);
if (module == null) continue;
foreach (var funcDef in ast.Definitions.OfType<NodeDefinitionFunc>())
{
@@ -149,14 +138,14 @@ public class ModuleGraph(Dictionary<string, ModuleGraph.Module> modules)
{
return node switch
{
NodeTypeBool type => new NubTypeBool(),
NodeTypeBool => new NubTypeBool(),
NodeTypeCustom type => ResolveStruct(type),
NodeTypeFunc type => new NubTypeFunc(type.Parameters.Select(Resolve).ToList(), Resolve(type.ReturnType)),
NodeTypePointer type => new NubTypePointer(Resolve(type.To)),
NodeTypeSInt type => new NubTypeSInt(type.Width),
NodeTypeUInt type => new NubTypeUInt(type.Width),
NodeTypeString type => new NubTypeString(),
NodeTypeVoid type => new NubTypeVoid(),
NodeTypeString => new NubTypeString(),
NodeTypeVoid => new NubTypeVoid(),
_ => throw new ArgumentOutOfRangeException(nameof(node))
};
}
@@ -167,8 +156,7 @@ public class ModuleGraph(Dictionary<string, ModuleGraph.Module> modules)
if (module == null)
throw new CompileException(Diagnostic.Error($"Unknown module: {type.Module.Ident}").Build());
var structType = module.ResolveStruct(type.Name.Ident);
if (structType == null)
if (!module.TryResolveStructType(type.Name.Ident, out var structType))
throw new CompileException(Diagnostic.Error($"Unknown custom type: {type.Module.Ident}::{type.Name.Ident}").Build());
return structType;