...
This commit is contained in:
@@ -20,13 +20,9 @@ public class Generator
|
|||||||
private readonly ModuleGraph moduleGraph;
|
private readonly ModuleGraph moduleGraph;
|
||||||
private readonly bool compileLib;
|
private readonly bool compileLib;
|
||||||
private readonly IndentedTextWriter writer = new();
|
private readonly IndentedTextWriter writer = new();
|
||||||
private readonly Dictionary<NubTypeStruct, string> structTypeNames = new();
|
|
||||||
|
|
||||||
private string Emit()
|
private string Emit()
|
||||||
{
|
{
|
||||||
foreach (var (i, structType) in moduleGraph.GetModules().SelectMany(x => x.GetCustomTypes().OfType<NubTypeStruct>().Index()))
|
|
||||||
structTypeNames[structType] = $"s{i}";
|
|
||||||
|
|
||||||
writer.WriteLine("""
|
writer.WriteLine("""
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
@@ -43,46 +39,61 @@ public class Generator
|
|||||||
|
|
||||||
writer.WriteLine();
|
writer.WriteLine();
|
||||||
|
|
||||||
foreach (var typeName in structTypeNames)
|
foreach (var module in moduleGraph.GetModules())
|
||||||
writer.WriteLine($"struct {typeName.Value};");
|
|
||||||
|
|
||||||
writer.WriteLine();
|
|
||||||
|
|
||||||
foreach (var typeName in structTypeNames)
|
|
||||||
{
|
{
|
||||||
|
foreach (var (name, info) in module.GetTypes())
|
||||||
|
{
|
||||||
|
if (info is Module.TypeInfoStruct s)
|
||||||
|
{
|
||||||
|
writer.WriteLine($"struct {Name.Create(module.Name, name, NubTypeStruct.Get(module.Name, name))};");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var module in moduleGraph.GetModules())
|
||||||
|
{
|
||||||
|
foreach (var (name, info) in module.GetTypes())
|
||||||
|
{
|
||||||
|
if (info is Module.TypeInfoStruct s)
|
||||||
|
{
|
||||||
|
writer.WriteLine();
|
||||||
writer.Write("struct ");
|
writer.Write("struct ");
|
||||||
|
|
||||||
if (typeName.Key.Packed)
|
if (s.Packed)
|
||||||
{
|
{
|
||||||
writer.Write("__attribute__((__packed__)) ");
|
writer.Write("__attribute__((__packed__)) ");
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.WriteLine(typeName.Value);
|
writer.WriteLine(Name.Create(module.Name, name, NubTypeStruct.Get(module.Name, name)));
|
||||||
writer.WriteLine("{");
|
writer.WriteLine("{");
|
||||||
using (writer.Indent())
|
using (writer.Indent())
|
||||||
{
|
{
|
||||||
foreach (var field in typeName.Key.Fields)
|
foreach (var field in s.Fields)
|
||||||
|
{
|
||||||
writer.WriteLine($"{CType(field.Type, field.Name)};");
|
writer.WriteLine($"{CType(field.Type, field.Name)};");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
writer.WriteLine("};");
|
writer.WriteLine("};");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
writer.WriteLine();
|
writer.WriteLine();
|
||||||
|
|
||||||
foreach (var module in moduleGraph.GetModules())
|
foreach (var module in moduleGraph.GetModules())
|
||||||
{
|
{
|
||||||
foreach (var (name, type) in module.GetIdentifierTypes())
|
foreach (var (name, info) in module.GetIdentifiers())
|
||||||
{
|
{
|
||||||
if (type is NubTypeFunc fn)
|
if (info.Type is NubTypeFunc fn)
|
||||||
{
|
{
|
||||||
if (!functions.Any(x => x.GetMangledName() == SymbolNameGen.Exported(module.Name, name, type)))
|
if (!functions.Any(x => x.GetMangledName() == Name.Create(module.Name, name, info.Type)))
|
||||||
writer.Write("extern ");
|
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, Name.Create(module.Name, name, info.Type))}({string.Join(", ", fn.Parameters.Select(p => CType(p)))});");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
writer.WriteLine($"{CType(type, SymbolNameGen.Exported(module.Name, name, type))};");
|
writer.WriteLine($"{CType(info.Type, Name.Create(module.Name, name, info.Type))};");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -238,7 +249,7 @@ public class Generator
|
|||||||
TypedNodeExpressionStructLiteral expression => EmitExpressionStructLiteral(expression),
|
TypedNodeExpressionStructLiteral expression => EmitExpressionStructLiteral(expression),
|
||||||
TypedNodeExpressionMemberAccess expression => EmitExpressionMemberAccess(expression),
|
TypedNodeExpressionMemberAccess expression => EmitExpressionMemberAccess(expression),
|
||||||
TypedNodeExpressionLocalIdent expression => expression.Value.Ident,
|
TypedNodeExpressionLocalIdent expression => expression.Value.Ident,
|
||||||
TypedNodeExpressionModuleIdent expression => SymbolNameGen.Exported(expression.Module.Ident, expression.Value.Ident, expression.Type),
|
TypedNodeExpressionModuleIdent expression => Name.Create(expression.Module.Ident, expression.Value.Ident, expression.Type),
|
||||||
TypedNodeExpressionFuncCall expression => EmitExpressionFuncCall(expression),
|
TypedNodeExpressionFuncCall expression => EmitExpressionFuncCall(expression),
|
||||||
_ => throw new ArgumentOutOfRangeException(nameof(node), node, null)
|
_ => throw new ArgumentOutOfRangeException(nameof(node), node, null)
|
||||||
};
|
};
|
||||||
@@ -293,8 +304,9 @@ public class Generator
|
|||||||
}
|
}
|
||||||
|
|
||||||
var initializerStrings = initializerValues.Select(x => $".{x.Key} = {x.Value}");
|
var initializerStrings = initializerValues.Select(x => $".{x.Key} = {x.Value}");
|
||||||
|
var structType = (NubTypeStruct)expression.Type;
|
||||||
|
|
||||||
return $"(struct {structTypeNames[(NubTypeStruct)expression.Type]}){{ {string.Join(", ", initializerStrings)} }}";
|
return $"(struct {Name.Create(structType.Module, structType.Name, structType)}){{ {string.Join(", ", initializerStrings)} }}";
|
||||||
}
|
}
|
||||||
|
|
||||||
private string EmitExpressionMemberAccess(TypedNodeExpressionMemberAccess expression)
|
private string EmitExpressionMemberAccess(TypedNodeExpressionMemberAccess expression)
|
||||||
@@ -316,7 +328,7 @@ public class Generator
|
|||||||
{
|
{
|
||||||
NubTypeVoid => "void" + (varName != null ? $" {varName}" : ""),
|
NubTypeVoid => "void" + (varName != null ? $" {varName}" : ""),
|
||||||
NubTypeBool => "bool" + (varName != null ? $" {varName}" : ""),
|
NubTypeBool => "bool" + (varName != null ? $" {varName}" : ""),
|
||||||
NubTypeStruct type => $"struct {structTypeNames[type]}" + (varName != null ? $" {varName}" : ""),
|
NubTypeStruct type => $"struct {Name.Create(type.Module, type.Name, type)}" + (varName != null ? $" {varName}" : ""),
|
||||||
NubTypeSInt type => $"int{type.Width}_t" + (varName != null ? $" {varName}" : ""),
|
NubTypeSInt type => $"int{type.Width}_t" + (varName != null ? $" {varName}" : ""),
|
||||||
NubTypeUInt type => $"uint{type.Width}_t" + (varName != null ? $" {varName}" : ""),
|
NubTypeUInt type => $"uint{type.Width}_t" + (varName != null ? $" {varName}" : ""),
|
||||||
NubTypePointer type => CType(type.To) + (varName != null ? $" *{varName}" : "*"),
|
NubTypePointer type => CType(type.To) + (varName != null ? $" *{varName}" : "*"),
|
||||||
|
|||||||
@@ -25,113 +25,6 @@ public class ModuleGraph
|
|||||||
return module != null;
|
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
|
public class Builder
|
||||||
{
|
{
|
||||||
private readonly List<Ast> asts = [];
|
private readonly List<Ast> asts = [];
|
||||||
@@ -153,93 +46,78 @@ public class ModuleGraph
|
|||||||
|
|
||||||
var modules = new Dictionary<string, Module>();
|
var modules = new Dictionary<string, Module>();
|
||||||
|
|
||||||
// First pass: Register libraries
|
|
||||||
foreach (var manifest in manifests)
|
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);
|
switch (type)
|
||||||
modules.Add(manifestModule.Name, module);
|
{
|
||||||
|
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.AddIdentifier(name, new Module.IdentifierInfo(identifier.Exported, identifier.Type));
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var astModuleCache = new Dictionary<Ast, Module>();
|
|
||||||
|
|
||||||
// Second pass: Register modules from ast
|
|
||||||
foreach (var ast in asts)
|
foreach (var ast in asts)
|
||||||
{
|
{
|
||||||
if (!modules.ContainsKey(ast.ModuleName.Ident))
|
var module = GetOrCreateModule(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];
|
|
||||||
|
|
||||||
foreach (var structDef in ast.Definitions.OfType<NodeDefinitionStruct>())
|
foreach (var structDef in ast.Definitions.OfType<NodeDefinitionStruct>())
|
||||||
{
|
{
|
||||||
var type = NubTypeStruct.CreateWithoutFields(structDef.Packed);
|
module.AddType(structDef.Name.Ident, new Module.TypeInfoStruct(structDef.Exported, structDef.Packed));
|
||||||
var info = new Module.CustomTypeInfo(type, structDef.Exported, Module.Source.Ast);
|
|
||||||
module.AddCustomType(structDef.Name.Ident, info);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fourth pass: Resolve struct fields
|
|
||||||
foreach (var ast in asts)
|
foreach (var ast in asts)
|
||||||
{
|
{
|
||||||
var module = astModuleCache[ast];
|
var module = GetOrCreateModule(ast.ModuleName.Ident);
|
||||||
|
|
||||||
foreach (var structDef in ast.Definitions.OfType<NodeDefinitionStruct>())
|
foreach (var structDef in ast.Definitions.OfType<NodeDefinitionStruct>())
|
||||||
{
|
{
|
||||||
if (!module.TryResolveCustomType(structDef.Name.Ident, true, out var customType))
|
if (!module.TryResolveType(structDef.Name.Ident, true, out var typeInfo))
|
||||||
throw new UnreachableException($"{nameof(customType)} should always be registered");
|
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);
|
structType.SetFields(fields);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fifth pass: Register identifiers
|
|
||||||
foreach (var ast in asts)
|
foreach (var ast in asts)
|
||||||
{
|
{
|
||||||
var module = astModuleCache[ast];
|
var module = GetOrCreateModule(ast.ModuleName.Ident);
|
||||||
|
|
||||||
foreach (var funcDef in ast.Definitions.OfType<NodeDefinitionFunc>())
|
foreach (var funcDef in ast.Definitions.OfType<NodeDefinitionFunc>())
|
||||||
{
|
{
|
||||||
var parameters = funcDef.Parameters.Select(x => ResolveType(x.Type, module.Name)).ToList();
|
var parameters = funcDef.Parameters.Select(x => ResolveType(x.Type, module.Name)).ToList();
|
||||||
var returnType = ResolveType(funcDef.ReturnType, module.Name);
|
var returnType = ResolveType(funcDef.ReturnType, module.Name);
|
||||||
var funcType = NubTypeFunc.Get(parameters, returnType);
|
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);
|
module.AddIdentifier(funcDef.Name.Ident, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var globalVariable in ast.Definitions.OfType<NodeDefinitionGlobalVariable>())
|
foreach (var globalVariable in ast.Definitions.OfType<NodeDefinitionGlobalVariable>())
|
||||||
{
|
{
|
||||||
var type = ResolveType(globalVariable.Type, module.Name);
|
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);
|
module.AddIdentifier(globalVariable.Name.Ident, info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -273,16 +151,117 @@ public class ModuleGraph
|
|||||||
|
|
||||||
var includePrivate = currentModule == type.Module.Ident;
|
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());
|
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 class Module(string name)
|
||||||
public record ManifestModule(string Name, Dictionary<string, ManifestCustomTypeInfo> CustomTypes, Dictionary<string, ManifestIdentifierInfo> Identifiers);
|
{
|
||||||
public record ManifestCustomTypeInfo(string EncodedType, bool Exported);
|
public string Name { get; } = name;
|
||||||
public record ManifestIdentifierInfo(string EncodedType, bool Exported);
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace Compiler;
|
namespace Compiler;
|
||||||
|
|
||||||
@@ -32,7 +33,7 @@ public class NubLib
|
|||||||
fileStream.CopyTo(entryStream);
|
fileStream.CopyTo(entryStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static NublibLoadResult Unpack(string nublibPath)
|
public static NubLibLoadResult Unpack(string nublibPath)
|
||||||
{
|
{
|
||||||
using var fs = new FileStream(nublibPath, FileMode.Open, FileAccess.Read);
|
using var fs = new FileStream(nublibPath, FileMode.Open, FileAccess.Read);
|
||||||
using var zip = new ZipArchive(fs, ZipArchiveMode.Read);
|
using var zip = new ZipArchive(fs, ZipArchiveMode.Read);
|
||||||
@@ -55,8 +56,48 @@ public class NubLib
|
|||||||
entryStream.CopyTo(tempFile);
|
entryStream.CopyTo(tempFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new NublibLoadResult(manifest, tempArchivePath);
|
return new NubLibLoadResult(manifest, tempArchivePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
public record NublibLoadResult(Manifest Manifest, string ArchivePath);
|
public record NubLibLoadResult(Manifest Manifest, string ArchivePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public record Manifest(Dictionary<string, Manifest.Module> Modules)
|
||||||
|
{
|
||||||
|
public static Manifest Create(ModuleGraph moduleGraph)
|
||||||
|
{
|
||||||
|
var modules = new Dictionary<string, Module>();
|
||||||
|
|
||||||
|
foreach (var module in moduleGraph.GetModules())
|
||||||
|
{
|
||||||
|
var types = module.GetTypes().ToDictionary(x => x.Key, x => ConvertType(x.Value));
|
||||||
|
var identifiers = module.GetIdentifiers().ToDictionary(x => x.Key, x => new Module.IdentifierInfo(x.Value.Exported, x.Value.Type));
|
||||||
|
modules[module.Name] = new Module(types, identifiers);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Manifest(modules);
|
||||||
|
|
||||||
|
static Module.TypeInfo ConvertType(Compiler.Module.TypeInfo typeInfo)
|
||||||
|
{
|
||||||
|
return typeInfo switch
|
||||||
|
{
|
||||||
|
Compiler.Module.TypeInfoStruct s => new Module.TypeInfoStruct(s.Exported, s.Packed, s.Fields.Select(x => new Module.TypeInfoStruct.Field(x.Name, x.Type)).ToList()),
|
||||||
|
_ => throw new ArgumentOutOfRangeException(nameof(typeInfo))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public record Module(Dictionary<string, Module.TypeInfo> Types, Dictionary<string, Module.IdentifierInfo> Identifiers)
|
||||||
|
{
|
||||||
|
public record IdentifierInfo(bool Exported, NubType Type);
|
||||||
|
|
||||||
|
[JsonDerivedType(typeof(TypeInfoStruct), "struct")]
|
||||||
|
public abstract record TypeInfo(bool Exported);
|
||||||
|
|
||||||
|
public record TypeInfoStruct(bool Exported, bool Packed, IReadOnlyList<TypeInfoStruct.Field> Fields) : TypeInfo(Exported)
|
||||||
|
{
|
||||||
|
public record Field(string Name, NubType Type);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,10 @@
|
|||||||
using System.Diagnostics;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace Compiler;
|
namespace Compiler;
|
||||||
|
|
||||||
|
[JsonConverter(typeof(NubTypeJsonConverter))]
|
||||||
public abstract class NubType
|
public abstract class NubType
|
||||||
{
|
{
|
||||||
public abstract override string ToString();
|
public abstract override string ToString();
|
||||||
@@ -87,61 +89,26 @@ public class NubTypeString : NubType
|
|||||||
|
|
||||||
public class NubTypeStruct : NubType
|
public class NubTypeStruct : NubType
|
||||||
{
|
{
|
||||||
private static readonly Dictionary<Signature, NubTypeStruct> Cache = new();
|
private static readonly Dictionary<(string Module, string Name), NubTypeStruct> Cache = new();
|
||||||
|
|
||||||
public static NubTypeStruct Get(bool packed, List<Field> fields)
|
public static NubTypeStruct Get(string module, string name)
|
||||||
{
|
{
|
||||||
var sig = new Signature(packed, fields);
|
if (!Cache.TryGetValue((module, name), out var structType))
|
||||||
|
Cache[(module, name)] = structType = new NubTypeStruct(module, name);
|
||||||
|
|
||||||
if (!Cache.TryGetValue(sig, out var sturctType))
|
return structType;
|
||||||
Cache[sig] = sturctType = new NubTypeStruct(packed, fields);
|
|
||||||
|
|
||||||
return sturctType;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private NubTypeStruct(bool packed, List<Field> fields)
|
private NubTypeStruct(string module, string name)
|
||||||
{
|
{
|
||||||
Packed = packed;
|
Module = module;
|
||||||
this.fields = fields;
|
Name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
private NubTypeStruct(bool packed)
|
public string Module { get; }
|
||||||
{
|
public string Name { get; }
|
||||||
Packed = packed;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Packed { get; }
|
public override string ToString() => $"struct {Module}::{Name}";
|
||||||
|
|
||||||
private IReadOnlyList<Field>? fields;
|
|
||||||
public IReadOnlyList<Field> Fields
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (fields == null)
|
|
||||||
throw new InvalidOperationException("Fields has not been set");
|
|
||||||
|
|
||||||
return fields;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static NubTypeStruct CreateWithoutFields(bool packed)
|
|
||||||
{
|
|
||||||
return new NubTypeStruct(packed);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetFields(List<Field> fields)
|
|
||||||
{
|
|
||||||
if (this.fields != null)
|
|
||||||
throw new InvalidOperationException("Fields can only be set once");
|
|
||||||
|
|
||||||
this.fields = fields;
|
|
||||||
Cache[new Signature(Packed, this.fields)] = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString() => $"struct {{ {string.Join(' ', Fields.Select(f => $"{f.Name}: {f.Type}"))} }}";
|
|
||||||
|
|
||||||
public record Field(string Name, NubType Type);
|
|
||||||
private record Signature(bool Packed, IReadOnlyList<Field> Fields);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class NubTypePointer : NubType
|
public class NubTypePointer : NubType
|
||||||
@@ -183,7 +150,7 @@ public class NubTypeFunc : NubType
|
|||||||
public IReadOnlyList<NubType> Parameters { get; }
|
public IReadOnlyList<NubType> Parameters { get; }
|
||||||
public NubType ReturnType { get; }
|
public NubType ReturnType { get; }
|
||||||
|
|
||||||
public string MangledName(string name, string module) => SymbolNameGen.Exported(name, module, this);
|
public string MangledName(string name, string module) => Name.Create(name, module, this);
|
||||||
|
|
||||||
private NubTypeFunc(List<NubType> parameters, NubType returnType)
|
private NubTypeFunc(List<NubType> parameters, NubType returnType)
|
||||||
{
|
{
|
||||||
@@ -212,15 +179,7 @@ public class TypeEncoder
|
|||||||
private string EncodeRoot(NubType type)
|
private string EncodeRoot(NubType type)
|
||||||
{
|
{
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
|
|
||||||
EncodeType(sb, type);
|
EncodeType(sb, type);
|
||||||
|
|
||||||
foreach (var definition in structDefinitions.Values.OrderBy(x => x.Index))
|
|
||||||
{
|
|
||||||
Debug.Assert(definition.Encoded != null);
|
|
||||||
sb.Insert(0, definition.Encoded);
|
|
||||||
}
|
|
||||||
|
|
||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -259,7 +218,11 @@ public class TypeEncoder
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case NubTypeStruct st:
|
case NubTypeStruct st:
|
||||||
sb.Append(GetOrCreateStructDefinition(st));
|
sb.Append("T(");
|
||||||
|
sb.Append(st.Module);
|
||||||
|
sb.Append(':');
|
||||||
|
sb.Append(st.Name);
|
||||||
|
sb.Append(')');
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NubTypeFunc fn:
|
case NubTypeFunc fn:
|
||||||
@@ -277,35 +240,6 @@ public class TypeEncoder
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetOrCreateStructDefinition(NubTypeStruct st)
|
|
||||||
{
|
|
||||||
if (!structDefinitions.TryGetValue(st, out var definition))
|
|
||||||
{
|
|
||||||
definition = new Definition(structDefinitions.Count);
|
|
||||||
structDefinitions[st] = definition;
|
|
||||||
|
|
||||||
var sb = new StringBuilder();
|
|
||||||
|
|
||||||
sb.Append("D(");
|
|
||||||
sb.Append(st.Packed ? '1' : '0');
|
|
||||||
sb.Append('{');
|
|
||||||
for (var i = 0; i < st.Fields.Count; i++)
|
|
||||||
{
|
|
||||||
var field = st.Fields[i];
|
|
||||||
sb.Append(field.Name);
|
|
||||||
sb.Append(':');
|
|
||||||
EncodeType(sb, field.Type);
|
|
||||||
}
|
|
||||||
sb.Append('}');
|
|
||||||
sb.Append(')');
|
|
||||||
|
|
||||||
var encoded = sb.ToString();
|
|
||||||
definition.Encoded = encoded;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $"T({definition.Index})";
|
|
||||||
}
|
|
||||||
|
|
||||||
private class Definition(int index)
|
private class Definition(int index)
|
||||||
{
|
{
|
||||||
public int Index { get; } = index;
|
public int Index { get; } = index;
|
||||||
@@ -317,7 +251,7 @@ public class TypeDecoder
|
|||||||
{
|
{
|
||||||
public static NubType Decode(string encoded)
|
public static NubType Decode(string encoded)
|
||||||
{
|
{
|
||||||
return new TypeDecoder(encoded).DecodeRoot();
|
return new TypeDecoder(encoded).DecodeType();
|
||||||
}
|
}
|
||||||
|
|
||||||
private TypeDecoder(string encoded)
|
private TypeDecoder(string encoded)
|
||||||
@@ -326,66 +260,7 @@ public class TypeDecoder
|
|||||||
}
|
}
|
||||||
|
|
||||||
private readonly string encoded;
|
private readonly string encoded;
|
||||||
private int index;
|
private int index = 0;
|
||||||
private readonly List<NubTypeStruct> structDefinitions = new();
|
|
||||||
|
|
||||||
private NubType DecodeRoot()
|
|
||||||
{
|
|
||||||
// First pass: Collect all declarations
|
|
||||||
while (TryExpect('D'))
|
|
||||||
{
|
|
||||||
Expect('(');
|
|
||||||
var packedChar = Consume();
|
|
||||||
if (packedChar is not '1' and not '0')
|
|
||||||
throw new Exception("Expected '0' or '1' for struct packing");
|
|
||||||
|
|
||||||
Expect('{');
|
|
||||||
while (TryPeek(out var c))
|
|
||||||
{
|
|
||||||
Consume();
|
|
||||||
if (c == '}')
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
Expect(')');
|
|
||||||
|
|
||||||
structDefinitions.Add(NubTypeStruct.CreateWithoutFields(packedChar == '1'));
|
|
||||||
}
|
|
||||||
|
|
||||||
index = 0;
|
|
||||||
var defIndex = 0;
|
|
||||||
|
|
||||||
// Second pass: Set field types
|
|
||||||
while (TryExpect('D'))
|
|
||||||
{
|
|
||||||
var fields = new List<NubTypeStruct.Field>();
|
|
||||||
|
|
||||||
Consume();
|
|
||||||
Consume();
|
|
||||||
Consume();
|
|
||||||
|
|
||||||
while (!TryExpect('}'))
|
|
||||||
{
|
|
||||||
var sb = new StringBuilder();
|
|
||||||
|
|
||||||
while (!TryExpect(':'))
|
|
||||||
{
|
|
||||||
sb.Append(Consume());
|
|
||||||
}
|
|
||||||
|
|
||||||
var type = DecodeType();
|
|
||||||
|
|
||||||
fields.Add(new NubTypeStruct.Field(sb.ToString(), type));
|
|
||||||
}
|
|
||||||
Expect(')');
|
|
||||||
|
|
||||||
structDefinitions[defIndex].SetFields(fields);
|
|
||||||
|
|
||||||
defIndex += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return DecodeType();
|
|
||||||
}
|
|
||||||
|
|
||||||
private NubType DecodeType()
|
private NubType DecodeType()
|
||||||
{
|
{
|
||||||
@@ -443,10 +318,21 @@ public class TypeDecoder
|
|||||||
|
|
||||||
private NubTypeStruct DecodeStruct()
|
private NubTypeStruct DecodeStruct()
|
||||||
{
|
{
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
|
||||||
Expect('(');
|
Expect('(');
|
||||||
var index = ExpectInt();
|
while (!TryExpect(':'))
|
||||||
Expect(')');
|
sb.Append(Consume());
|
||||||
return structDefinitions[index];
|
|
||||||
|
var module = sb.ToString();
|
||||||
|
sb.Clear();
|
||||||
|
|
||||||
|
while (!TryExpect(')'))
|
||||||
|
sb.Append(Consume());
|
||||||
|
|
||||||
|
var name = sb.ToString();
|
||||||
|
|
||||||
|
return NubTypeStruct.Get(module, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool TryPeek(out char c)
|
private bool TryPeek(out char c)
|
||||||
@@ -517,6 +403,19 @@ public class TypeDecoder
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class NubTypeJsonConverter : JsonConverter<NubType>
|
||||||
|
{
|
||||||
|
public override NubType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||||
|
{
|
||||||
|
return TypeDecoder.Decode(reader.GetString()!);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Write(Utf8JsonWriter writer, NubType value, JsonSerializerOptions options)
|
||||||
|
{
|
||||||
|
writer.WriteStringValue(TypeEncoder.Encode(value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class Hashing
|
public static class Hashing
|
||||||
{
|
{
|
||||||
public static ulong Fnv1a64(string text)
|
public static ulong Fnv1a64(string text)
|
||||||
@@ -535,14 +434,14 @@ public static class Hashing
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class SymbolNameGen
|
public static class Name
|
||||||
{
|
{
|
||||||
public static string Exported(string module, string function, NubType type)
|
public static string Create(string module, string name, NubType type)
|
||||||
{
|
{
|
||||||
var canonical = TypeEncoder.Encode(type);
|
var canonical = TypeEncoder.Encode(type);
|
||||||
var hash = Hashing.Fnv1a64(canonical);
|
var hash = Hashing.Fnv1a64(canonical);
|
||||||
|
|
||||||
return $"nub_{Sanitize(module)}_{Sanitize(function)}_{hash:x16}";
|
return $"nub_{Sanitize(module)}_{Sanitize(name)}_{hash:x16}";
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string Sanitize(string s)
|
private static string Sanitize(string s)
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ if (compileLib)
|
|||||||
File.WriteAllText(".build/out.c", output);
|
File.WriteAllText(".build/out.c", output);
|
||||||
Process.Start("gcc", ["-Og", "-fvisibility=hidden", "-fno-builtin", "-c", "-o", ".build/out.o", ".build/out.c", .. archivePaths]).WaitForExit();
|
Process.Start("gcc", ["-Og", "-fvisibility=hidden", "-fno-builtin", "-c", "-o", ".build/out.o", ".build/out.c", .. archivePaths]).WaitForExit();
|
||||||
Process.Start("ar", ["rcs", ".build/out.a", ".build/out.o"]).WaitForExit();
|
Process.Start("ar", ["rcs", ".build/out.a", ".build/out.o"]).WaitForExit();
|
||||||
NubLib.Pack(".build/out.nublib", ".build/out.a", moduleGraph.CreateManifest());
|
NubLib.Pack(".build/out.nublib", ".build/out.a", Manifest.Create(moduleGraph));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -313,10 +313,10 @@ public class TypeChecker
|
|||||||
|
|
||||||
var includePrivate = expression.Module.Ident == moduleName;
|
var includePrivate = expression.Module.Ident == moduleName;
|
||||||
|
|
||||||
if (!module.TryResolveIdentifierType(expression.Value.Ident, includePrivate, out var identifierType))
|
if (!module.TryResolveIdentifier(expression.Value.Ident, includePrivate, out var identifierType))
|
||||||
throw new CompileException(Diagnostic.Error($"Identifier '{expression.Module.Ident}::{expression.Value.Ident}' not found").At(fileName, expression.Value).Build());
|
throw new CompileException(Diagnostic.Error($"Identifier '{expression.Module.Ident}::{expression.Value.Ident}' not found").At(fileName, expression.Value).Build());
|
||||||
|
|
||||||
return new TypedNodeExpressionModuleIdent(expression.Tokens, identifierType, expression.Module, expression.Value);
|
return new TypedNodeExpressionModuleIdent(expression.Tokens, identifierType.Type, expression.Module, expression.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private TypedNodeExpressionIntLiteral CheckExpressionIntLiteral(NodeExpressionIntLiteral expression)
|
private TypedNodeExpressionIntLiteral CheckExpressionIntLiteral(NodeExpressionIntLiteral expression)
|
||||||
@@ -327,14 +327,27 @@ public class TypeChecker
|
|||||||
private TypedNodeExpressionMemberAccess CheckExpressionMemberAccess(NodeExpressionMemberAccess expression)
|
private TypedNodeExpressionMemberAccess CheckExpressionMemberAccess(NodeExpressionMemberAccess expression)
|
||||||
{
|
{
|
||||||
var target = CheckExpression(expression.Target);
|
var target = CheckExpression(expression.Target);
|
||||||
if (target.Type is not NubTypeStruct structType)
|
|
||||||
throw new CompileException(Diagnostic.Error($"Cannot access member of non-struct type {target.Type}").At(fileName, target).Build());
|
|
||||||
|
|
||||||
var field = structType.Fields.FirstOrDefault(x => x.Name == expression.Name.Ident);
|
switch (target.Type)
|
||||||
|
{
|
||||||
|
case NubTypeStruct structType:
|
||||||
|
if (!moduleGraph.TryResolveModule(structType.Module, out var module))
|
||||||
|
throw new CompileException(Diagnostic.Error($"Module '{structType.Module}' not found").At(fileName, expression.Target).Build());
|
||||||
|
|
||||||
|
if (!module.TryResolveType(structType.Name, moduleName == structType.Module, out var typeDef))
|
||||||
|
throw new CompileException(Diagnostic.Error($"Type '{structType.Name}' not found in module '{structType.Module}'").At(fileName, expression.Target).Build());
|
||||||
|
|
||||||
|
if (typeDef is not Module.TypeInfoStruct structDef)
|
||||||
|
throw new CompileException(Diagnostic.Error($"Type '{structType.Module}::{structType.Name}' is not a struct").At(fileName, expression.Target).Build());
|
||||||
|
|
||||||
|
var field = structDef.Fields.FirstOrDefault(x => x.Name == expression.Name.Ident);
|
||||||
if (field == null)
|
if (field == null)
|
||||||
throw new CompileException(Diagnostic.Error($"Struct '{target.Type}' does not have a field matching the name '{expression.Name.Ident}'").At(fileName, target).Build());
|
throw new CompileException(Diagnostic.Error($"Struct '{target.Type}' does not have a field matching the name '{expression.Name.Ident}'").At(fileName, target).Build());
|
||||||
|
|
||||||
return new TypedNodeExpressionMemberAccess(expression.Tokens, field.Type, target, expression.Name);
|
return new TypedNodeExpressionMemberAccess(expression.Tokens, field.Type, target, expression.Name);
|
||||||
|
default:
|
||||||
|
throw new CompileException(Diagnostic.Error($"{target.Type} has no member '{expression.Name.Ident}'").At(fileName, target).Build());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private TypedNodeExpressionFuncCall CheckExpressionFuncCall(NodeExpressionFuncCall expression)
|
private TypedNodeExpressionFuncCall CheckExpressionFuncCall(NodeExpressionFuncCall expression)
|
||||||
@@ -360,16 +373,16 @@ public class TypeChecker
|
|||||||
|
|
||||||
var includePrivate = expression.Module.Ident == moduleName;
|
var includePrivate = expression.Module.Ident == moduleName;
|
||||||
|
|
||||||
if (!module.TryResolveCustomType(expression.Name.Ident, includePrivate, out var customType))
|
if (!module.TryResolveType(expression.Name.Ident, includePrivate, out var typeDef))
|
||||||
throw new CompileException(Diagnostic.Error($"Struct '{expression.Module.Ident}::{expression.Name.Ident}' not found").At(fileName, expression.Name).Build());
|
throw new CompileException(Diagnostic.Error($"Struct '{expression.Module.Ident}::{expression.Name.Ident}' not found").At(fileName, expression.Name).Build());
|
||||||
|
|
||||||
if (customType is not NubTypeStruct structType)
|
if (typeDef is not Module.TypeInfoStruct structDef)
|
||||||
throw new CompileException(Diagnostic.Error($"Cannot create struct literal of non-struct type '{expression.Module.Ident}::{expression.Name.Ident}'").At(fileName, expression.Name).Build());
|
throw new CompileException(Diagnostic.Error($"Cannot create struct literal of non-struct type '{expression.Module.Ident}::{expression.Name.Ident}'").At(fileName, expression.Name).Build());
|
||||||
|
|
||||||
var initializers = new List<TypedNodeExpressionStructLiteral.Initializer>();
|
var initializers = new List<TypedNodeExpressionStructLiteral.Initializer>();
|
||||||
foreach (var initializer in expression.Initializers)
|
foreach (var initializer in expression.Initializers)
|
||||||
{
|
{
|
||||||
var field = structType.Fields.FirstOrDefault(x => x.Name == initializer.Name.Ident);
|
var field = structDef.Fields.FirstOrDefault(x => x.Name == initializer.Name.Ident);
|
||||||
if (field == null)
|
if (field == null)
|
||||||
throw new CompileException(Diagnostic.Error($"Field '{initializer.Name.Ident}' does not exist on struct '{expression.Name.Ident}'").At(fileName, initializer.Name).Build());
|
throw new CompileException(Diagnostic.Error($"Field '{initializer.Name.Ident}' does not exist on struct '{expression.Name.Ident}'").At(fileName, initializer.Name).Build());
|
||||||
|
|
||||||
@@ -380,7 +393,7 @@ public class TypeChecker
|
|||||||
initializers.Add(new TypedNodeExpressionStructLiteral.Initializer(initializer.Tokens, initializer.Name, value));
|
initializers.Add(new TypedNodeExpressionStructLiteral.Initializer(initializer.Tokens, initializer.Name, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
return new TypedNodeExpressionStructLiteral(expression.Tokens, structType, initializers);
|
return new TypedNodeExpressionStructLiteral(expression.Tokens, NubTypeStruct.Get(expression.Module.Ident, expression.Name.Ident), initializers);
|
||||||
}
|
}
|
||||||
|
|
||||||
private NubType ResolveType(NodeType node)
|
private NubType ResolveType(NodeType node)
|
||||||
@@ -406,10 +419,14 @@ public class TypeChecker
|
|||||||
|
|
||||||
var includePrivate = type.Module.Ident == moduleName;
|
var includePrivate = type.Module.Ident == moduleName;
|
||||||
|
|
||||||
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($"Custom type '{type.Module.Ident}::{type.Name.Ident}' not found").At(fileName, type.Name).Build());
|
throw new CompileException(Diagnostic.Error($"Custom type '{type.Module.Ident}::{type.Name.Ident}' not found").At(fileName, type.Name).Build());
|
||||||
|
|
||||||
return customType;
|
return customType switch
|
||||||
|
{
|
||||||
|
Module.TypeInfoStruct => NubTypeStruct.Get(type.Module.Ident, type.Name.Ident),
|
||||||
|
_ => throw new ArgumentOutOfRangeException(nameof(customType))
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private sealed class Scope
|
private sealed class Scope
|
||||||
@@ -479,7 +496,7 @@ public class TypedNodeDefinitionFunc(List<Token> tokens, string module, TokenIde
|
|||||||
|
|
||||||
public string GetMangledName()
|
public string GetMangledName()
|
||||||
{
|
{
|
||||||
return SymbolNameGen.Exported(Module, Name.Ident, GetNubType());
|
return Compiler.Name.Create(Module, Name.Ident, GetNubType());
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Param(List<Token> tokens, TokenIdent name, NubType type) : TypedNode(tokens)
|
public class Param(List<Token> tokens, TokenIdent name, NubType type) : TypedNode(tokens)
|
||||||
|
|||||||
Reference in New Issue
Block a user