...
This commit is contained in:
@@ -25,113 +25,6 @@ public class ModuleGraph
|
||||
return module != null;
|
||||
}
|
||||
|
||||
public Manifest CreateManifest()
|
||||
{
|
||||
return new Manifest(1, GetModules().Select(x => x.CreateManifestModule()).ToList());
|
||||
}
|
||||
|
||||
public class Module(string name)
|
||||
{
|
||||
public string Name { get; } = name;
|
||||
private readonly Dictionary<string, CustomTypeInfo> customTypes = new();
|
||||
private readonly Dictionary<string, IdentifierInfo> identifierTypes = new();
|
||||
|
||||
public IReadOnlyList<NubType> GetCustomTypes()
|
||||
{
|
||||
return customTypes.Values.Select(x => x.Type).ToList();
|
||||
}
|
||||
|
||||
public IReadOnlyDictionary<string, NubType> GetIdentifierTypes()
|
||||
{
|
||||
return identifierTypes.ToDictionary(x => x.Key, x => x.Value.Type);
|
||||
}
|
||||
|
||||
public bool TryResolveCustomType(string name, bool searchPrivate, [NotNullWhen(true)] out NubType? customType)
|
||||
{
|
||||
var info = customTypes.GetValueOrDefault(name);
|
||||
if (info == null)
|
||||
{
|
||||
customType = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (info.Exported || searchPrivate)
|
||||
{
|
||||
customType = info.Type;
|
||||
return true;
|
||||
}
|
||||
|
||||
customType = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryResolveIdentifierType(string name, bool searchPrivate, [NotNullWhen(true)] out NubType? identifierType)
|
||||
{
|
||||
var info = identifierTypes.GetValueOrDefault(name);
|
||||
if (info == null)
|
||||
{
|
||||
identifierType = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (info.Exported || searchPrivate)
|
||||
{
|
||||
identifierType = info.Type;
|
||||
return true;
|
||||
}
|
||||
|
||||
identifierType = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public void AddCustomType(string name, CustomTypeInfo info)
|
||||
{
|
||||
customTypes.Add(name, info);
|
||||
}
|
||||
|
||||
public void AddIdentifier(string name, IdentifierInfo info)
|
||||
{
|
||||
identifierTypes.Add(name, info);
|
||||
}
|
||||
|
||||
public ManifestModule CreateManifestModule()
|
||||
{
|
||||
var manifestCustomTypes = customTypes.ToDictionary(x => x.Key, x => x.Value.CreateManifestCustomTypeInfo());
|
||||
var manifestIdentifiers = identifierTypes.ToDictionary(x => x.Key, x => x.Value.CreateManifestIdentifierInfo());
|
||||
return new ManifestModule(Name, manifestCustomTypes, manifestIdentifiers);
|
||||
}
|
||||
|
||||
public enum Source
|
||||
{
|
||||
Ast,
|
||||
Lib,
|
||||
}
|
||||
|
||||
public class CustomTypeInfo(NubType type, bool exported, Source source)
|
||||
{
|
||||
public NubType Type { get; } = type;
|
||||
public bool Exported { get; } = exported;
|
||||
public Source Source { get; } = source;
|
||||
|
||||
public ManifestCustomTypeInfo CreateManifestCustomTypeInfo()
|
||||
{
|
||||
return new ManifestCustomTypeInfo(TypeEncoder.Encode(Type), Exported);
|
||||
}
|
||||
}
|
||||
|
||||
public class IdentifierInfo(NubType type, bool exported, Source source)
|
||||
{
|
||||
public NubType Type { get; } = type;
|
||||
public bool Exported { get; } = exported;
|
||||
public Source Source { get; } = source;
|
||||
|
||||
public ManifestIdentifierInfo CreateManifestIdentifierInfo()
|
||||
{
|
||||
return new ManifestIdentifierInfo(TypeEncoder.Encode(Type), Exported);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class Builder
|
||||
{
|
||||
private readonly List<Ast> asts = [];
|
||||
@@ -153,93 +46,78 @@ public class ModuleGraph
|
||||
|
||||
var modules = new Dictionary<string, Module>();
|
||||
|
||||
// First pass: Register libraries
|
||||
foreach (var manifest in manifests)
|
||||
{
|
||||
foreach (var manifestModule in manifest.Modules)
|
||||
foreach (var (moduleName, manifestModule) in manifest.Modules)
|
||||
{
|
||||
if (!modules.TryGetValue(manifestModule.Name, out var module))
|
||||
var module = GetOrCreateModule(moduleName);
|
||||
|
||||
foreach (var (name, type) in manifestModule.Types)
|
||||
{
|
||||
module = new Module(manifestModule.Name);
|
||||
modules.Add(manifestModule.Name, module);
|
||||
switch (type)
|
||||
{
|
||||
case Manifest.Module.TypeInfoStruct s:
|
||||
var info = new Module.TypeInfoStruct(s.Exported, s.Packed);
|
||||
var fields = s.Fields.Select(x => new Module.TypeInfoStruct.Field(x.Name, x.Type)).ToList();
|
||||
info.SetFields(fields);
|
||||
module.AddType(name, info);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(type));
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var customType in manifestModule.CustomTypes)
|
||||
foreach (var (name, identifier) in manifestModule.Identifiers)
|
||||
{
|
||||
var decoded = TypeDecoder.Decode(customType.Value.EncodedType);
|
||||
module.AddCustomType(customType.Key, new Module.CustomTypeInfo(decoded, customType.Value.Exported, Module.Source.Lib));
|
||||
}
|
||||
|
||||
foreach (var identifier in manifestModule.Identifiers)
|
||||
{
|
||||
var decoded = TypeDecoder.Decode(identifier.Value.EncodedType);
|
||||
module.AddIdentifier(identifier.Key, new Module.IdentifierInfo(decoded, identifier.Value.Exported, Module.Source.Lib));
|
||||
module.AddIdentifier(name, new Module.IdentifierInfo(identifier.Exported, identifier.Type));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var astModuleCache = new Dictionary<Ast, Module>();
|
||||
|
||||
// Second pass: Register modules from ast
|
||||
foreach (var ast in asts)
|
||||
{
|
||||
if (!modules.ContainsKey(ast.ModuleName.Ident))
|
||||
{
|
||||
var module = new Module(ast.ModuleName.Ident);
|
||||
modules.Add(ast.ModuleName.Ident, module);
|
||||
astModuleCache[ast] = module;
|
||||
}
|
||||
}
|
||||
|
||||
// Third pass: Register struct types without fields
|
||||
foreach (var ast in asts)
|
||||
{
|
||||
var module = astModuleCache[ast];
|
||||
var module = GetOrCreateModule(ast.ModuleName.Ident);
|
||||
|
||||
foreach (var structDef in ast.Definitions.OfType<NodeDefinitionStruct>())
|
||||
{
|
||||
var type = NubTypeStruct.CreateWithoutFields(structDef.Packed);
|
||||
var info = new Module.CustomTypeInfo(type, structDef.Exported, Module.Source.Ast);
|
||||
module.AddCustomType(structDef.Name.Ident, info);
|
||||
module.AddType(structDef.Name.Ident, new Module.TypeInfoStruct(structDef.Exported, structDef.Packed));
|
||||
}
|
||||
}
|
||||
|
||||
// Fourth pass: Resolve struct fields
|
||||
foreach (var ast in asts)
|
||||
{
|
||||
var module = astModuleCache[ast];
|
||||
var module = GetOrCreateModule(ast.ModuleName.Ident);
|
||||
|
||||
foreach (var structDef in ast.Definitions.OfType<NodeDefinitionStruct>())
|
||||
{
|
||||
if (!module.TryResolveCustomType(structDef.Name.Ident, true, out var customType))
|
||||
throw new UnreachableException($"{nameof(customType)} should always be registered");
|
||||
if (!module.TryResolveType(structDef.Name.Ident, true, out var typeInfo))
|
||||
throw new UnreachableException($"{nameof(typeInfo)} should always be registered");
|
||||
|
||||
if (customType is NubTypeStruct structType)
|
||||
if (typeInfo is Module.TypeInfoStruct structType)
|
||||
{
|
||||
var fields = structDef.Fields.Select(f => new NubTypeStruct.Field(f.Name.Ident, ResolveType(f.Type, module.Name))).ToList();
|
||||
var fields = structDef.Fields.Select(f => new Module.TypeInfoStruct.Field(f.Name.Ident, ResolveType(f.Type, module.Name))).ToList();
|
||||
structType.SetFields(fields);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fifth pass: Register identifiers
|
||||
foreach (var ast in asts)
|
||||
{
|
||||
var module = astModuleCache[ast];
|
||||
var module = GetOrCreateModule(ast.ModuleName.Ident);
|
||||
|
||||
foreach (var funcDef in ast.Definitions.OfType<NodeDefinitionFunc>())
|
||||
{
|
||||
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);
|
||||
var info = new Module.IdentifierInfo(funcType, funcDef.Exported, Module.Source.Ast);
|
||||
var info = new Module.IdentifierInfo(funcDef.Exported, funcType);
|
||||
module.AddIdentifier(funcDef.Name.Ident, info);
|
||||
}
|
||||
|
||||
foreach (var globalVariable in ast.Definitions.OfType<NodeDefinitionGlobalVariable>())
|
||||
{
|
||||
var type = ResolveType(globalVariable.Type, module.Name);
|
||||
var info = new Module.IdentifierInfo(type, globalVariable.Exported, Module.Source.Ast);
|
||||
var info = new Module.IdentifierInfo(globalVariable.Exported, type);
|
||||
module.AddIdentifier(globalVariable.Name.Ident, info);
|
||||
}
|
||||
}
|
||||
@@ -273,16 +151,117 @@ public class ModuleGraph
|
||||
|
||||
var includePrivate = currentModule == type.Module.Ident;
|
||||
|
||||
if (!module.TryResolveCustomType(type.Name.Ident, includePrivate, out var customType))
|
||||
if (!module.TryResolveType(type.Name.Ident, includePrivate, out var customType))
|
||||
throw new CompileException(Diagnostic.Error($"Unknown custom type: {type.Module.Ident}::{type.Name.Ident}").Build());
|
||||
|
||||
return customType;
|
||||
return customType switch
|
||||
{
|
||||
Module.TypeInfoStruct => NubTypeStruct.Get(type.Module.Ident, type.Name.Ident),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(customType))
|
||||
};
|
||||
}
|
||||
|
||||
Module GetOrCreateModule(string name)
|
||||
{
|
||||
if (!modules.TryGetValue(name, out var module))
|
||||
{
|
||||
module = new Module(name);
|
||||
modules.Add(name, module);
|
||||
}
|
||||
|
||||
return module;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public record Manifest(int Version, IReadOnlyList<ManifestModule> Modules);
|
||||
public record ManifestModule(string Name, Dictionary<string, ManifestCustomTypeInfo> CustomTypes, Dictionary<string, ManifestIdentifierInfo> Identifiers);
|
||||
public record ManifestCustomTypeInfo(string EncodedType, bool Exported);
|
||||
public record ManifestIdentifierInfo(string EncodedType, bool Exported);
|
||||
public class Module(string name)
|
||||
{
|
||||
public string Name { get; } = name;
|
||||
|
||||
private Dictionary<string, TypeInfo> types = new();
|
||||
private Dictionary<string, IdentifierInfo> identifiers = new();
|
||||
|
||||
public IReadOnlyDictionary<string, TypeInfo> GetTypes() => types;
|
||||
public IReadOnlyDictionary<string, IdentifierInfo> GetIdentifiers() => identifiers;
|
||||
|
||||
public bool TryResolveType(string name, bool searchPrivate, [NotNullWhen(true)] out TypeInfo? customType)
|
||||
{
|
||||
var info = types.GetValueOrDefault(name);
|
||||
if (info == null)
|
||||
{
|
||||
customType = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (info.Exported || searchPrivate)
|
||||
{
|
||||
customType = info;
|
||||
return true;
|
||||
}
|
||||
|
||||
customType = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryResolveIdentifier(string name, bool searchPrivate, [NotNullWhen(true)] out IdentifierInfo? identifierType)
|
||||
{
|
||||
var info = identifiers.GetValueOrDefault(name);
|
||||
if (info == null)
|
||||
{
|
||||
identifierType = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (info.Exported || searchPrivate)
|
||||
{
|
||||
identifierType = info;
|
||||
return true;
|
||||
}
|
||||
|
||||
identifierType = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public void AddType(string name, TypeInfo info)
|
||||
{
|
||||
types.Add(name, info);
|
||||
}
|
||||
|
||||
public void AddIdentifier(string name, IdentifierInfo info)
|
||||
{
|
||||
identifiers.Add(name, info);
|
||||
}
|
||||
|
||||
public class IdentifierInfo(bool exported, NubType type)
|
||||
{
|
||||
public bool Exported { get; } = exported;
|
||||
public NubType Type { get; } = type;
|
||||
}
|
||||
|
||||
|
||||
public abstract class TypeInfo(bool exported)
|
||||
{
|
||||
public bool Exported { get; } = exported;
|
||||
}
|
||||
|
||||
|
||||
public class TypeInfoStruct(bool exported, bool packed) : TypeInfo(exported)
|
||||
{
|
||||
private IReadOnlyList<Field>? fields;
|
||||
|
||||
public bool Packed { get; } = packed;
|
||||
public IReadOnlyList<Field> Fields => fields ?? throw new InvalidOperationException("Fields has not been set yet");
|
||||
|
||||
public void SetFields(IReadOnlyList<Field> fields)
|
||||
{
|
||||
this.fields = fields;
|
||||
}
|
||||
|
||||
public class Field(string name, NubType type)
|
||||
{
|
||||
public string Name { get; } = name;
|
||||
public NubType Type { get; } = type;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user