...
This commit is contained in:
246
compiler/NubLang/Modules/ModuleRepository.cs
Normal file
246
compiler/NubLang/Modules/ModuleRepository.cs
Normal file
@@ -0,0 +1,246 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using NubLang.Ast;
|
||||
using NubLang.Diagnostics;
|
||||
using NubLang.Syntax;
|
||||
using NubLang.Types;
|
||||
|
||||
namespace NubLang.Modules;
|
||||
|
||||
public sealed class ModuleRepository
|
||||
{
|
||||
public static ModuleRepository Create(List<SyntaxTree> syntaxTrees)
|
||||
{
|
||||
var structTypes = new Dictionary<(string module, string name), NubStructType>();
|
||||
var enumTypes = new Dictionary<(string module, string name), NubIntType>();
|
||||
|
||||
foreach (var syntaxTree in syntaxTrees)
|
||||
{
|
||||
var module = syntaxTree.TopLevelSyntaxNodes.OfType<ModuleSyntax>().FirstOrDefault();
|
||||
if (module == null)
|
||||
{
|
||||
throw new CompileException(Diagnostic.Error("Module declaration missing").WithHelp("module \"main\"").Build());
|
||||
}
|
||||
|
||||
foreach (var structSyntax in syntaxTree.TopLevelSyntaxNodes.OfType<StructSyntax>())
|
||||
{
|
||||
// note(nub31): Since not all struct types are registered yet, we cannot register field types as they might reference unregistered structs
|
||||
var key = (module.NameToken.Value, structSyntax.NameToken.Value);
|
||||
structTypes.Add(key, new NubStructType(module.NameToken.Value, structSyntax.NameToken.Value, structSyntax.Packed, []));
|
||||
}
|
||||
|
||||
foreach (var enumSyntax in syntaxTree.TopLevelSyntaxNodes.OfType<EnumSyntax>())
|
||||
{
|
||||
NubIntType? underlyingType = null;
|
||||
if (enumSyntax.Type != null)
|
||||
{
|
||||
if (enumSyntax.Type is not IntTypeSyntax intType)
|
||||
{
|
||||
throw new CompileException(Diagnostic.Error("Underlying type of enum must be an integer type").At(enumSyntax.Type).Build());
|
||||
}
|
||||
|
||||
underlyingType = new NubIntType(intType.Signed, intType.Width);
|
||||
}
|
||||
|
||||
underlyingType ??= new NubIntType(false, 64);
|
||||
|
||||
var key = (module.NameToken.Value, enumSyntax.NameToken.Value);
|
||||
enumTypes.Add(key, underlyingType);
|
||||
}
|
||||
}
|
||||
|
||||
// note(nub31): Since all struct types are now registered, we can safely resolve the field types
|
||||
foreach (var syntaxTree in syntaxTrees)
|
||||
{
|
||||
var module = syntaxTree.TopLevelSyntaxNodes.OfType<ModuleSyntax>().FirstOrDefault();
|
||||
if (module == null)
|
||||
{
|
||||
throw new CompileException(Diagnostic.Error("Module declaration missing").WithHelp("module \"main\"").Build());
|
||||
}
|
||||
|
||||
foreach (var structSyntax in syntaxTree.TopLevelSyntaxNodes.OfType<StructSyntax>())
|
||||
{
|
||||
var key = (module.NameToken.Value, structSyntax.NameToken.Value);
|
||||
|
||||
structTypes[key].Fields = structSyntax.Fields
|
||||
.Select(x => new NubStructFieldType(x.NameToken.Value, ResolveType(x.Type, module.NameToken.Value), x.Value != null))
|
||||
.ToList();
|
||||
}
|
||||
}
|
||||
|
||||
var modules = new Dictionary<string, Module>();
|
||||
|
||||
foreach (var syntaxTree in syntaxTrees)
|
||||
{
|
||||
var moduleDecl = syntaxTree.TopLevelSyntaxNodes.OfType<ModuleSyntax>().FirstOrDefault();
|
||||
if (moduleDecl == null)
|
||||
{
|
||||
throw new CompileException(Diagnostic.Error("Module declaration missing").WithHelp("module \"main\"").Build());
|
||||
}
|
||||
|
||||
var functionPrototypes = new List<FuncPrototypeNode>();
|
||||
|
||||
foreach (var funcSyntax in syntaxTree.TopLevelSyntaxNodes.OfType<FuncSyntax>())
|
||||
{
|
||||
var returnType = ResolveType(funcSyntax.Prototype.ReturnType, moduleDecl.NameToken.Value);
|
||||
var parameters = funcSyntax.Prototype.Parameters.Select(x => new FuncParameterNode(x.Tokens, x.NameToken, ResolveType(x.Type, moduleDecl.NameToken.Value))).ToList();
|
||||
functionPrototypes.Add(new FuncPrototypeNode(funcSyntax.Prototype.Tokens, funcSyntax.Prototype.NameToken, funcSyntax.Prototype.ExternSymbolToken, parameters, returnType));
|
||||
}
|
||||
|
||||
var module = new Module
|
||||
{
|
||||
Name = moduleDecl.NameToken.Value,
|
||||
StructTypes = structTypes.Where(x => x.Key.module == moduleDecl.NameToken.Value).Select(x => x.Value).ToList(),
|
||||
EnumTypes = enumTypes
|
||||
.Where(x => x.Key.module == moduleDecl.NameToken.Value)
|
||||
.ToDictionary(x => x.Key.name, x => x.Value),
|
||||
FunctionPrototypes = functionPrototypes
|
||||
};
|
||||
|
||||
modules.Add(moduleDecl.NameToken.Value, module);
|
||||
}
|
||||
|
||||
return new ModuleRepository(modules);
|
||||
|
||||
NubType ResolveType(TypeSyntax type, string currentModule)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
ArrayTypeSyntax arr => new NubArrayType(ResolveType(arr.BaseType, currentModule)),
|
||||
BoolTypeSyntax => new NubBoolType(),
|
||||
IntTypeSyntax i => new NubIntType(i.Signed, i.Width),
|
||||
FloatTypeSyntax f => new NubFloatType(f.Width),
|
||||
FuncTypeSyntax func => new NubFuncType(func.Parameters.Select(x => ResolveType(x, currentModule)).ToList(), ResolveType(func.ReturnType, currentModule)),
|
||||
SliceTypeSyntax slice => new NubSliceType(ResolveType(slice.BaseType, currentModule)),
|
||||
ConstArrayTypeSyntax arr => new NubConstArrayType(ResolveType(arr.BaseType, currentModule), arr.Size),
|
||||
PointerTypeSyntax ptr => new NubPointerType(ResolveType(ptr.BaseType, currentModule)),
|
||||
StringTypeSyntax => new NubStringType(),
|
||||
CustomTypeSyntax c => ResolveCustomType(c, currentModule),
|
||||
VoidTypeSyntax => new NubVoidType(),
|
||||
_ => throw new NotSupportedException($"Unknown type syntax: {type}")
|
||||
};
|
||||
}
|
||||
|
||||
NubType ResolveCustomType(CustomTypeSyntax customType, string currentModule)
|
||||
{
|
||||
var customTypeKey = (customType.ModuleToken?.Value ?? currentModule, customType.NameToken.Value);
|
||||
|
||||
var resolvedStructType = structTypes.GetValueOrDefault(customTypeKey);
|
||||
if (resolvedStructType != null)
|
||||
{
|
||||
return resolvedStructType;
|
||||
}
|
||||
|
||||
var resolvedEnumType = enumTypes.GetValueOrDefault(customTypeKey);
|
||||
if (resolvedEnumType != null)
|
||||
{
|
||||
return resolvedEnumType;
|
||||
}
|
||||
|
||||
throw new CompileException(Diagnostic
|
||||
.Error($"Type {customType.NameToken.Value} not found in module {customType.ModuleToken?.Value ?? currentModule}")
|
||||
.At(customType)
|
||||
.Build());
|
||||
}
|
||||
}
|
||||
|
||||
private ModuleRepository(Dictionary<string, Module> modules)
|
||||
{
|
||||
_modules = modules;
|
||||
}
|
||||
|
||||
private readonly Dictionary<string, Module> _modules;
|
||||
|
||||
public Module Get(IdentifierToken ident)
|
||||
{
|
||||
var module = _modules.GetValueOrDefault(ident.Value);
|
||||
if (module == null)
|
||||
{
|
||||
throw new CompileException(Diagnostic.Error($"Module {ident.Value} was not found").At(ident).Build());
|
||||
}
|
||||
|
||||
return module;
|
||||
}
|
||||
|
||||
public sealed class Module
|
||||
{
|
||||
public required string Name { get; init; }
|
||||
public required List<FuncPrototypeNode> FunctionPrototypes { get; init; } = [];
|
||||
public required List<NubStructType> StructTypes { get; init; } = [];
|
||||
public required Dictionary<string, NubIntType> EnumTypes { get; init; } = [];
|
||||
|
||||
public bool TryResolveFunc(IdentifierToken name, [NotNullWhen(true)] out FuncPrototypeNode? value, [NotNullWhen(false)] out Diagnostic? diagnostic)
|
||||
{
|
||||
value = FunctionPrototypes.FirstOrDefault(x => x.NameToken.Value == name.Value);
|
||||
|
||||
if (value == null)
|
||||
{
|
||||
value = null;
|
||||
diagnostic = Diagnostic.Error($"Func {name.Value} not found in module {Name}").At(name).Build();
|
||||
return false;
|
||||
}
|
||||
|
||||
diagnostic = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
public FuncPrototypeNode ResolveFunc(IdentifierToken name)
|
||||
{
|
||||
if (!TryResolveFunc(name, out var value, out var diagnostic))
|
||||
{
|
||||
throw new CompileException(diagnostic);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public bool TryResolveStruct(IdentifierToken name, [NotNullWhen(true)] out NubStructType? value, [NotNullWhen(false)] out Diagnostic? diagnostic)
|
||||
{
|
||||
value = StructTypes.FirstOrDefault(x => x.Name == name.Value);
|
||||
|
||||
if (value == null)
|
||||
{
|
||||
value = null;
|
||||
diagnostic = Diagnostic.Error($"Struct {name.Value} not found in module {Name}").At(name).Build();
|
||||
return false;
|
||||
}
|
||||
|
||||
diagnostic = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
public NubStructType ResolveStruct(IdentifierToken name)
|
||||
{
|
||||
if (!TryResolveStruct(name, out var value, out var diagnostic))
|
||||
{
|
||||
throw new CompileException(diagnostic);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public bool TryResolveEnum(IdentifierToken name, [NotNullWhen(true)] out NubIntType? value, [NotNullWhen(false)] out Diagnostic? diagnostic)
|
||||
{
|
||||
value = EnumTypes.GetValueOrDefault(name.Value);
|
||||
|
||||
if (value == null)
|
||||
{
|
||||
value = null;
|
||||
diagnostic = Diagnostic.Error($"Enum {name.Value} not found in module {Name}").At(name).Build();
|
||||
return false;
|
||||
}
|
||||
|
||||
diagnostic = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
public NubIntType ResolveEnum(IdentifierToken name)
|
||||
{
|
||||
if (!TryResolveEnum(name, out var value, out var diagnostic))
|
||||
{
|
||||
throw new CompileException(diagnostic);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user