Module system
This commit is contained in:
@@ -60,7 +60,7 @@ foreach (var file in options.Files)
|
|||||||
syntaxTrees.Add(syntaxTree);
|
syntaxTrees.Add(syntaxTree);
|
||||||
}
|
}
|
||||||
|
|
||||||
var moduleSignatures = ModuleSignature.CollectFromSyntaxTrees(syntaxTrees);
|
var moduleSignatures = Module.CollectFromSyntaxTrees(syntaxTrees);
|
||||||
|
|
||||||
var definitions = new List<DefinitionNode>();
|
var definitions = new List<DefinitionNode>();
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
namespace NubLang.Code;
|
namespace NubLang.Code;
|
||||||
|
|
||||||
public readonly struct SourceLocation : IEquatable<SourceLocation>
|
public readonly struct SourceLocation : IEquatable<SourceLocation>, IComparable<SourceLocation>
|
||||||
{
|
{
|
||||||
public static SourceLocation Zero => new(0, 0);
|
public static SourceLocation Zero => new(0, 0);
|
||||||
|
|
||||||
@@ -39,4 +39,10 @@ public readonly struct SourceLocation : IEquatable<SourceLocation>
|
|||||||
public static bool operator >(SourceLocation left, SourceLocation right) => left.Line > right.Line || (left.Line == right.Line && left.Column > right.Column);
|
public static bool operator >(SourceLocation left, SourceLocation right) => left.Line > right.Line || (left.Line == right.Line && left.Column > right.Column);
|
||||||
public static bool operator <=(SourceLocation left, SourceLocation right) => left.Line <= right.Line || (left.Line == right.Line && left.Column <= right.Column);
|
public static bool operator <=(SourceLocation left, SourceLocation right) => left.Line <= right.Line || (left.Line == right.Line && left.Column <= right.Column);
|
||||||
public static bool operator >=(SourceLocation left, SourceLocation right) => left.Line >= right.Line || (left.Line == right.Line && left.Column >= right.Column);
|
public static bool operator >=(SourceLocation left, SourceLocation right) => left.Line >= right.Line || (left.Line == right.Line && left.Column >= right.Column);
|
||||||
|
|
||||||
|
public int CompareTo(SourceLocation other)
|
||||||
|
{
|
||||||
|
var lineComparison = Line.CompareTo(other.Line);
|
||||||
|
return lineComparison != 0 ? lineComparison : Column.CompareTo(other.Column);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
namespace NubLang.Code;
|
namespace NubLang.Code;
|
||||||
|
|
||||||
public readonly struct SourceSpan : IEquatable<SourceSpan>
|
public readonly struct SourceSpan : IEquatable<SourceSpan>, IComparable<SourceSpan>
|
||||||
{
|
{
|
||||||
public static SourceSpan Zero => new(SourceLocation.Zero, SourceLocation.Zero);
|
public static SourceSpan Zero => new(SourceLocation.Zero, SourceLocation.Zero);
|
||||||
|
|
||||||
@@ -54,4 +54,15 @@ public readonly struct SourceSpan : IEquatable<SourceSpan>
|
|||||||
|
|
||||||
public static bool operator ==(SourceSpan left, SourceSpan right) => Equals(left, right);
|
public static bool operator ==(SourceSpan left, SourceSpan right) => Equals(left, right);
|
||||||
public static bool operator !=(SourceSpan left, SourceSpan right) => !Equals(left, right);
|
public static bool operator !=(SourceSpan left, SourceSpan right) => !Equals(left, right);
|
||||||
|
|
||||||
|
public static bool operator <(SourceSpan left, SourceSpan right) => left.CompareTo(right) < 0;
|
||||||
|
public static bool operator <=(SourceSpan left, SourceSpan right) => left.CompareTo(right) <= 0;
|
||||||
|
public static bool operator >(SourceSpan left, SourceSpan right) => left.CompareTo(right) > 0;
|
||||||
|
public static bool operator >=(SourceSpan left, SourceSpan right) => left.CompareTo(right) >= 0;
|
||||||
|
|
||||||
|
public int CompareTo(SourceSpan other)
|
||||||
|
{
|
||||||
|
var startComparison = Start.CompareTo(other.Start);
|
||||||
|
return startComparison != 0 ? startComparison : End.CompareTo(other.End);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -27,7 +27,7 @@ public class Diagnostic
|
|||||||
var first = node.Tokens.FirstOrDefault();
|
var first = node.Tokens.FirstOrDefault();
|
||||||
if (first?.FileSpan != null)
|
if (first?.FileSpan != null)
|
||||||
{
|
{
|
||||||
var span = SourceSpan.Merge(node.Tokens.Select(x => x.FileSpan?.Span ?? SourceSpan.Zero));
|
var span = SourceSpan.Merge(node.Tokens.Select(x => x.FileSpan.Span));
|
||||||
At(new SourceFileSpan(first.FileSpan.SourceFile, span));
|
At(new SourceFileSpan(first.FileSpan.SourceFile, span));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ public class QBEGenerator
|
|||||||
{
|
{
|
||||||
private readonly QBEWriter _writer;
|
private readonly QBEWriter _writer;
|
||||||
private readonly IReadOnlyList<DefinitionNode> _definitions;
|
private readonly IReadOnlyList<DefinitionNode> _definitions;
|
||||||
private readonly IReadOnlyDictionary<string, ModuleSignature> _moduleSignatures;
|
private readonly IReadOnlyDictionary<string, Module> _moduleSignatures;
|
||||||
|
|
||||||
private readonly List<CStringLiteral> _cStringLiterals = [];
|
private readonly List<CStringLiteral> _cStringLiterals = [];
|
||||||
private readonly List<StringLiteral> _stringLiterals = [];
|
private readonly List<StringLiteral> _stringLiterals = [];
|
||||||
@@ -23,7 +23,7 @@ public class QBEGenerator
|
|||||||
private int _stringLiteralIndex;
|
private int _stringLiteralIndex;
|
||||||
private bool _codeIsReachable = true;
|
private bool _codeIsReachable = true;
|
||||||
|
|
||||||
public QBEGenerator(IReadOnlyList<DefinitionNode> definitions, IReadOnlyDictionary<string, ModuleSignature> moduleSignatures)
|
public QBEGenerator(IReadOnlyList<DefinitionNode> definitions, IReadOnlyDictionary<string, Module> moduleSignatures)
|
||||||
{
|
{
|
||||||
_definitions = definitions;
|
_definitions = definitions;
|
||||||
_moduleSignatures = moduleSignatures;
|
_moduleSignatures = moduleSignatures;
|
||||||
@@ -46,7 +46,7 @@ public class QBEGenerator
|
|||||||
{
|
{
|
||||||
foreach (var structType in signature.ExportedStructTypes)
|
foreach (var structType in signature.ExportedStructTypes)
|
||||||
{
|
{
|
||||||
EmitStructType(module, structType);
|
EmitStructType(module, structType.StructType);
|
||||||
_writer.NewLine();
|
_writer.NewLine();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -410,8 +410,6 @@ public class QBEGenerator
|
|||||||
|
|
||||||
private void EmitStructDefinition(StructNode structDef)
|
private void EmitStructDefinition(StructNode structDef)
|
||||||
{
|
{
|
||||||
var type = TypeResolver.ResolveStructType(structDef.Module, structDef.Name, _moduleSignatures);
|
|
||||||
|
|
||||||
// _writer.WriteLine($"export function {StructCtorName(_module.Name, structDef.Name)}() {{");
|
// _writer.WriteLine($"export function {StructCtorName(_module.Name, structDef.Name)}() {{");
|
||||||
// _writer.WriteLine("@start");
|
// _writer.WriteLine("@start");
|
||||||
// _writer.Indented($"%struct =l alloc8 {SizeOf(type)}");
|
// _writer.Indented($"%struct =l alloc8 {SizeOf(type)}");
|
||||||
@@ -660,7 +658,6 @@ public class QBEGenerator
|
|||||||
|
|
||||||
private string EmitFuncIdentifier(FuncIdentifierNode funcIdent)
|
private string EmitFuncIdentifier(FuncIdentifierNode funcIdent)
|
||||||
{
|
{
|
||||||
// todo(nub31): Support for extern funcs
|
|
||||||
return FuncName(funcIdent.Module, funcIdent.Name);
|
return FuncName(funcIdent.Module, funcIdent.Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -755,9 +752,7 @@ public class QBEGenerator
|
|||||||
private string EmitAddressOfStructFieldAccess(StructFieldAccessNode structFieldAccess)
|
private string EmitAddressOfStructFieldAccess(StructFieldAccessNode structFieldAccess)
|
||||||
{
|
{
|
||||||
var target = EmitExpression(structFieldAccess.Target);
|
var target = EmitExpression(structFieldAccess.Target);
|
||||||
|
var offset = OffsetOf(structFieldAccess.StructType, structFieldAccess.Field);
|
||||||
var structType = TypeResolver.ResolveStructType(structFieldAccess.StructType.Module, structFieldAccess.StructType.Name, _moduleSignatures);
|
|
||||||
var offset = OffsetOf(structType, structFieldAccess.Field);
|
|
||||||
|
|
||||||
var address = TmpName();
|
var address = TmpName();
|
||||||
_writer.Indented($"{address} =l add {target}, {offset}");
|
_writer.Indented($"{address} =l add {target}, {offset}");
|
||||||
@@ -1398,8 +1393,8 @@ public class QBEGenerator
|
|||||||
|
|
||||||
private string FuncName(string module, string name)
|
private string FuncName(string module, string name)
|
||||||
{
|
{
|
||||||
var type = TypeResolver.ResolveFunctionType(module, name, _moduleSignatures);
|
var function = _moduleSignatures[module].AllFunctions.First(x => x.Name == name);
|
||||||
var symbol = type.ExternSymbol ?? $"{module}.{name}";
|
var symbol = function.ExternSymbol ?? $"{module}.{name}";
|
||||||
return "$" + symbol;
|
return "$" + symbol;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -474,7 +474,7 @@ public sealed class Parser
|
|||||||
var expr = token switch
|
var expr = token switch
|
||||||
{
|
{
|
||||||
LiteralToken literal => new LiteralSyntax(GetTokens(startIndex), literal.Value, literal.Kind),
|
LiteralToken literal => new LiteralSyntax(GetTokens(startIndex), literal.Value, literal.Kind),
|
||||||
IdentifierToken identifier => new LocalIdentifierSyntax(GetTokens(startIndex), identifier.Value),
|
IdentifierToken identifier => ParseIdentifier(startIndex, identifier),
|
||||||
SymbolToken symbolToken => symbolToken.Symbol switch
|
SymbolToken symbolToken => symbolToken.Symbol switch
|
||||||
{
|
{
|
||||||
Symbol.OpenParen => ParseParenthesizedExpression(),
|
Symbol.OpenParen => ParseParenthesizedExpression(),
|
||||||
@@ -499,6 +499,17 @@ public sealed class Parser
|
|||||||
return ParsePostfixOperators(expr);
|
return ParsePostfixOperators(expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ExpressionSyntax ParseIdentifier(int startIndex, IdentifierToken identifier)
|
||||||
|
{
|
||||||
|
if (TryExpectSymbol(Symbol.DoubleColon))
|
||||||
|
{
|
||||||
|
var name = ExpectIdentifier();
|
||||||
|
return new ModuleIdentifierSyntax(GetTokens(startIndex), identifier.Value, name.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new LocalIdentifierSyntax(GetTokens(startIndex), identifier.Value);
|
||||||
|
}
|
||||||
|
|
||||||
private ExpressionSyntax ParseParenthesizedExpression()
|
private ExpressionSyntax ParseParenthesizedExpression()
|
||||||
{
|
{
|
||||||
var expression = ParseExpression();
|
var expression = ParseExpression();
|
||||||
@@ -690,14 +701,27 @@ public sealed class Parser
|
|||||||
return new FloatTypeSyntax(GetTokens(startIndex), size);
|
return new FloatTypeSyntax(GetTokens(startIndex), size);
|
||||||
}
|
}
|
||||||
|
|
||||||
return name.Value switch
|
switch (name.Value)
|
||||||
{
|
{
|
||||||
"void" => new VoidTypeSyntax(GetTokens(startIndex)),
|
case "void":
|
||||||
"string" => new StringTypeSyntax(GetTokens(startIndex)),
|
return new VoidTypeSyntax(GetTokens(startIndex));
|
||||||
"cstring" => new CStringTypeSyntax(GetTokens(startIndex)),
|
case "string":
|
||||||
"bool" => new BoolTypeSyntax(GetTokens(startIndex)),
|
return new StringTypeSyntax(GetTokens(startIndex));
|
||||||
_ => new CustomTypeSyntax(GetTokens(startIndex), _moduleName, name.Value)
|
case "cstring":
|
||||||
};
|
return new CStringTypeSyntax(GetTokens(startIndex));
|
||||||
|
case "bool":
|
||||||
|
return new BoolTypeSyntax(GetTokens(startIndex));
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
if (TryExpectSymbol(Symbol.DoubleColon))
|
||||||
|
{
|
||||||
|
var customTypeName = ExpectIdentifier().Value;
|
||||||
|
return new CustomTypeSyntax(GetTokens(startIndex), name.Value, customTypeName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new CustomTypeSyntax(GetTokens(startIndex), _moduleName, name.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TryExpectSymbol(Symbol.Caret))
|
if (TryExpectSymbol(Symbol.Caret))
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ public enum Symbol
|
|||||||
Break,
|
Break,
|
||||||
Continue,
|
Continue,
|
||||||
Colon,
|
Colon,
|
||||||
|
DoubleColon,
|
||||||
OpenParen,
|
OpenParen,
|
||||||
CloseParen,
|
CloseParen,
|
||||||
OpenBrace,
|
OpenBrace,
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ public sealed class Tokenizer
|
|||||||
[['>', '>']] = Symbol.RightShift,
|
[['>', '>']] = Symbol.RightShift,
|
||||||
[['&', '&']] = Symbol.And,
|
[['&', '&']] = Symbol.And,
|
||||||
[['|', '|']] = Symbol.Or,
|
[['|', '|']] = Symbol.Or,
|
||||||
|
[[':', ':']] = Symbol.DoubleColon,
|
||||||
[[':']] = Symbol.Colon,
|
[[':']] = Symbol.Colon,
|
||||||
[['(']] = Symbol.OpenParen,
|
[['(']] = Symbol.OpenParen,
|
||||||
[[')']] = Symbol.CloseParen,
|
[[')']] = Symbol.CloseParen,
|
||||||
|
|||||||
@@ -3,11 +3,11 @@ using NubLang.TypeChecking.Node;
|
|||||||
|
|
||||||
namespace NubLang.TypeChecking;
|
namespace NubLang.TypeChecking;
|
||||||
|
|
||||||
public class ModuleSignature
|
public class Module
|
||||||
{
|
{
|
||||||
public static IReadOnlyDictionary<string, ModuleSignature> CollectFromSyntaxTrees(IReadOnlyList<SyntaxTree> syntaxTrees)
|
public static IReadOnlyDictionary<string, Module> CollectFromSyntaxTrees(IReadOnlyList<SyntaxTree> syntaxTrees)
|
||||||
{
|
{
|
||||||
var modules = new Dictionary<string, ModuleSignature>();
|
var modules = new Dictionary<string, Module>();
|
||||||
|
|
||||||
foreach (var syntaxTree in syntaxTrees)
|
foreach (var syntaxTree in syntaxTrees)
|
||||||
{
|
{
|
||||||
@@ -15,7 +15,7 @@ public class ModuleSignature
|
|||||||
|
|
||||||
if (!modules.TryGetValue(moduleName, out var module))
|
if (!modules.TryGetValue(moduleName, out var module))
|
||||||
{
|
{
|
||||||
module = new ModuleSignature();
|
module = new Module();
|
||||||
modules[moduleName] = module;
|
modules[moduleName] = module;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,11 +25,11 @@ public class ModuleSignature
|
|||||||
{
|
{
|
||||||
case FuncSyntax funcDef:
|
case FuncSyntax funcDef:
|
||||||
{
|
{
|
||||||
var parameters = funcDef.Signature.Parameters.Select(p => TypeResolver.ResolveType(p.Type, modules)).ToList();
|
var parameters = funcDef.Signature.Parameters.Select(p => ResolveType(p.Type)).ToList();
|
||||||
var returnType = TypeResolver.ResolveType(funcDef.Signature.ReturnType, modules);
|
var returnType = ResolveType(funcDef.Signature.ReturnType);
|
||||||
|
|
||||||
var type = new FuncTypeNode(parameters, returnType, funcDef.ExternSymbol);
|
var type = new FuncTypeNode(parameters, returnType);
|
||||||
module._functions.Add(funcDef.Name, new ModuleMember<FuncTypeNode>(type, def.Exported));
|
module._functions.Add(new ModuleFuncType(def.Exported, funcDef.Name, funcDef.ExternSymbol, type));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case InterfaceSyntax interfaceDef:
|
case InterfaceSyntax interfaceDef:
|
||||||
@@ -38,13 +38,13 @@ public class ModuleSignature
|
|||||||
for (var i = 0; i < interfaceDef.Functions.Count; i++)
|
for (var i = 0; i < interfaceDef.Functions.Count; i++)
|
||||||
{
|
{
|
||||||
var function = interfaceDef.Functions[i];
|
var function = interfaceDef.Functions[i];
|
||||||
var parameters = function.Signature.Parameters.Select(p => TypeResolver.ResolveType(p.Type, modules)).ToList();
|
var parameters = function.Signature.Parameters.Select(p => ResolveType(p.Type)).ToList();
|
||||||
var returnType = TypeResolver.ResolveType(function.Signature.ReturnType, modules);
|
var returnType = ResolveType(function.Signature.ReturnType);
|
||||||
functions.Add(new InterfaceTypeFunc(function.Name, new FuncTypeNode(parameters, returnType), i));
|
functions.Add(new InterfaceTypeFunc(function.Name, new FuncTypeNode(parameters, returnType), i));
|
||||||
}
|
}
|
||||||
|
|
||||||
var type = new InterfaceTypeNode(moduleName, interfaceDef.Name, functions);
|
var type = new InterfaceTypeNode(moduleName, interfaceDef.Name, functions);
|
||||||
module._interfaces.Add(new ModuleMember<InterfaceTypeNode>(type, def.Exported));
|
module._interfaces.Add(new ModuleInterfaceType(def.Exported, type));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case StructSyntax structDef:
|
case StructSyntax structDef:
|
||||||
@@ -52,14 +52,14 @@ public class ModuleSignature
|
|||||||
var fields = new List<StructTypeField>();
|
var fields = new List<StructTypeField>();
|
||||||
foreach (var field in structDef.Fields)
|
foreach (var field in structDef.Fields)
|
||||||
{
|
{
|
||||||
fields.Add(new StructTypeField(field.Name, TypeResolver.ResolveType(field.Type, modules), field.Index, field.Value.HasValue));
|
fields.Add(new StructTypeField(field.Name, ResolveType(field.Type), field.Index, field.Value.HasValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
var functions = new List<StructTypeFunc>();
|
var functions = new List<StructTypeFunc>();
|
||||||
foreach (var function in structDef.Functions)
|
foreach (var function in structDef.Functions)
|
||||||
{
|
{
|
||||||
var parameters = function.Signature.Parameters.Select(p => TypeResolver.ResolveType(p.Type, modules)).ToList();
|
var parameters = function.Signature.Parameters.Select(p => ResolveType(p.Type)).ToList();
|
||||||
var returnType = TypeResolver.ResolveType(function.Signature.ReturnType, modules);
|
var returnType = ResolveType(function.Signature.ReturnType);
|
||||||
functions.Add(new StructTypeFunc(function.Name, new FuncTypeNode(parameters, returnType)));
|
functions.Add(new StructTypeFunc(function.Name, new FuncTypeNode(parameters, returnType)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,7 +71,7 @@ public class ModuleSignature
|
|||||||
throw new Exception("Interface implementation is not a custom type");
|
throw new Exception("Interface implementation is not a custom type");
|
||||||
}
|
}
|
||||||
|
|
||||||
var resolvedType = TypeResolver.ResolveCustomType(customType.Module, customType.Name, modules);
|
var resolvedType = ResolveType(customType);
|
||||||
if (resolvedType is not InterfaceTypeNode interfaceType)
|
if (resolvedType is not InterfaceTypeNode interfaceType)
|
||||||
{
|
{
|
||||||
throw new Exception("Interface implementation is not a interface");
|
throw new Exception("Interface implementation is not a interface");
|
||||||
@@ -81,7 +81,7 @@ public class ModuleSignature
|
|||||||
}
|
}
|
||||||
|
|
||||||
var type = new StructTypeNode(moduleName, structDef.Name, fields, functions, interfaceImplementations);
|
var type = new StructTypeNode(moduleName, structDef.Name, fields, functions, interfaceImplementations);
|
||||||
module._structs.Add(new ModuleMember<StructTypeNode>(type, def.Exported));
|
module._structs.Add(new ModuleStructType(def.Exported, type));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -93,29 +93,97 @@ public class ModuleSignature
|
|||||||
}
|
}
|
||||||
|
|
||||||
return modules;
|
return modules;
|
||||||
|
|
||||||
|
TypeNode ResolveType(TypeSyntax type)
|
||||||
|
{
|
||||||
|
return type switch
|
||||||
|
{
|
||||||
|
BoolTypeSyntax => new BoolTypeNode(),
|
||||||
|
CStringTypeSyntax => new CStringTypeNode(),
|
||||||
|
IntTypeSyntax i => new IntTypeNode(i.Signed, i.Width),
|
||||||
|
CustomTypeSyntax c => ResolveCustomType(c.Module, c.Name),
|
||||||
|
FloatTypeSyntax f => new FloatTypeNode(f.Width),
|
||||||
|
FuncTypeSyntax func => new FuncTypeNode(func.Parameters.Select(ResolveType).ToList(), ResolveType(func.ReturnType)),
|
||||||
|
ArrayTypeSyntax arr => new ArrayTypeNode(ResolveType(arr.BaseType)),
|
||||||
|
PointerTypeSyntax ptr => new PointerTypeNode(ResolveType(ptr.BaseType)),
|
||||||
|
StringTypeSyntax => new StringTypeNode(),
|
||||||
|
VoidTypeSyntax => new VoidTypeNode(),
|
||||||
|
_ => throw new NotSupportedException($"Unknown type syntax: {type}")
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ModuleMember<T>
|
TypeNode ResolveCustomType(string moduleName, string typeName)
|
||||||
{
|
{
|
||||||
public ModuleMember(T value, bool exported)
|
if (!modules.TryGetValue(moduleName, out var module))
|
||||||
|
{
|
||||||
|
throw new Exception("Module not found: " + moduleName);
|
||||||
|
}
|
||||||
|
|
||||||
|
var structType = module.AllStructTypes.FirstOrDefault(x => x.StructType.Name == typeName);
|
||||||
|
if (structType != null)
|
||||||
|
{
|
||||||
|
return structType.StructType;
|
||||||
|
}
|
||||||
|
|
||||||
|
var interfaceType = module.AllInterfaceTypes.FirstOrDefault(x => x.InterfaceType.Name == typeName);
|
||||||
|
if (interfaceType != null)
|
||||||
|
{
|
||||||
|
return interfaceType.InterfaceType;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Exception($"Type {typeName} not found in module {moduleName}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly List<ModuleStructType> _structs = [];
|
||||||
|
private readonly List<ModuleInterfaceType> _interfaces = [];
|
||||||
|
private readonly List<ModuleFuncType> _functions = [];
|
||||||
|
|
||||||
|
public IReadOnlyList<ModuleStructType> ExportedStructTypes => _structs.Where(x => x.Exported).ToList();
|
||||||
|
public IReadOnlyList<ModuleInterfaceType> ExportedInterfaceTypes => _interfaces.Where(x => x.Exported).ToList();
|
||||||
|
public IReadOnlyList<ModuleFuncType> ExportedFunctions => _functions.Where(x => x.Exported).ToList();
|
||||||
|
|
||||||
|
public IReadOnlyList<ModuleStructType> AllStructTypes => _structs;
|
||||||
|
public IReadOnlyList<ModuleInterfaceType> AllInterfaceTypes => _interfaces;
|
||||||
|
public IReadOnlyList<ModuleFuncType> AllFunctions => _functions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ModuleStructType
|
||||||
|
{
|
||||||
|
public ModuleStructType(bool exported, StructTypeNode structType)
|
||||||
{
|
{
|
||||||
Value = value;
|
|
||||||
Exported = exported;
|
Exported = exported;
|
||||||
|
StructType = structType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public T Value { get; set; }
|
public bool Exported { get; }
|
||||||
public bool Exported { get; set; }
|
public StructTypeNode StructType { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly List<ModuleMember<StructTypeNode>> _structs = [];
|
public class ModuleInterfaceType
|
||||||
private readonly List<ModuleMember<InterfaceTypeNode>> _interfaces = [];
|
{
|
||||||
private readonly Dictionary<string, ModuleMember<FuncTypeNode>> _functions = [];
|
public ModuleInterfaceType(bool exported, InterfaceTypeNode interfaceType)
|
||||||
|
{
|
||||||
public IReadOnlyList<StructTypeNode> ExportedStructTypes => _structs.Where(x => x.Exported).Select(x => x.Value).ToList();
|
Exported = exported;
|
||||||
public IReadOnlyList<InterfaceTypeNode> ExportedInterfaceTypes => _interfaces.Where(x => x.Exported).Select(x => x.Value).ToList();
|
InterfaceType = interfaceType;
|
||||||
public IReadOnlyDictionary<string, FuncTypeNode> ExportedFunctions => _functions.Where(x => x.Value.Exported).ToDictionary(x => x.Key, x => x.Value.Value);
|
}
|
||||||
|
|
||||||
public IReadOnlyList<StructTypeNode> AllStructTypes => _structs.Select(x => x.Value).ToList();
|
public bool Exported { get; }
|
||||||
public IReadOnlyList<InterfaceTypeNode> AllInterfaceTypes => _interfaces.Select(x => x.Value).ToList();
|
public InterfaceTypeNode InterfaceType { get; }
|
||||||
public IReadOnlyDictionary<string, FuncTypeNode> AllFunctions => _functions.ToDictionary(x => x.Key, x => x.Value.Value);
|
}
|
||||||
|
|
||||||
|
public class ModuleFuncType
|
||||||
|
{
|
||||||
|
public ModuleFuncType(bool exported, string name, string? externSymbol, FuncTypeNode funcType)
|
||||||
|
{
|
||||||
|
Exported = exported;
|
||||||
|
Name = name;
|
||||||
|
ExternSymbol = externSymbol;
|
||||||
|
FuncType = funcType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Exported { get; }
|
||||||
|
public string Name { get; }
|
||||||
|
public string? ExternSymbol { get; }
|
||||||
|
public FuncTypeNode FuncType { get; }
|
||||||
}
|
}
|
||||||
@@ -110,9 +110,8 @@ public class BoolTypeNode : SimpleTypeNode
|
|||||||
public override int GetHashCode() => HashCode.Combine(typeof(BoolTypeNode));
|
public override int GetHashCode() => HashCode.Combine(typeof(BoolTypeNode));
|
||||||
}
|
}
|
||||||
|
|
||||||
public class FuncTypeNode(IReadOnlyList<TypeNode> parameters, TypeNode returnType, string? externSymbol = null) : SimpleTypeNode
|
public class FuncTypeNode(IReadOnlyList<TypeNode> parameters, TypeNode returnType) : SimpleTypeNode
|
||||||
{
|
{
|
||||||
public string? ExternSymbol { get; } = externSymbol;
|
|
||||||
public IReadOnlyList<TypeNode> Parameters { get; } = parameters;
|
public IReadOnlyList<TypeNode> Parameters { get; } = parameters;
|
||||||
public TypeNode ReturnType { get; } = returnType;
|
public TypeNode ReturnType { get; } = returnType;
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ namespace NubLang.TypeChecking;
|
|||||||
public sealed class TypeChecker
|
public sealed class TypeChecker
|
||||||
{
|
{
|
||||||
private readonly SyntaxTree _syntaxTree;
|
private readonly SyntaxTree _syntaxTree;
|
||||||
private readonly IReadOnlyDictionary<string, ModuleSignature> _moduleSignatures;
|
private readonly IReadOnlyDictionary<string, Module> _importedModules;
|
||||||
|
|
||||||
private readonly Stack<Scope> _scopes = [];
|
private readonly Stack<Scope> _scopes = [];
|
||||||
private readonly Stack<TypeNode> _funcReturnTypes = [];
|
private readonly Stack<TypeNode> _funcReturnTypes = [];
|
||||||
@@ -16,10 +16,10 @@ public sealed class TypeChecker
|
|||||||
|
|
||||||
private Scope Scope => _scopes.Peek();
|
private Scope Scope => _scopes.Peek();
|
||||||
|
|
||||||
public TypeChecker(SyntaxTree syntaxTree, IReadOnlyDictionary<string, ModuleSignature> moduleSignatures)
|
public TypeChecker(SyntaxTree syntaxTree, IReadOnlyDictionary<string, Module> moduleSignatures)
|
||||||
{
|
{
|
||||||
_syntaxTree = syntaxTree;
|
_syntaxTree = syntaxTree;
|
||||||
_moduleSignatures = moduleSignatures.Where(x => syntaxTree.Metadata.Imports.Contains(x.Key) || _syntaxTree.Metadata.ModuleName == x.Key).ToDictionary();
|
_importedModules = moduleSignatures.Where(x => syntaxTree.Metadata.Imports.Contains(x.Key) || _syntaxTree.Metadata.ModuleName == x.Key).ToDictionary();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IReadOnlyList<Diagnostic> GetDiagnostics() => _diagnostics;
|
public IReadOnlyList<Diagnostic> GetDiagnostics() => _diagnostics;
|
||||||
@@ -346,18 +346,43 @@ public sealed class TypeChecker
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Second, look in the current module for a function matching the identifier
|
// Second, look in the current module for a function matching the identifier
|
||||||
var module = _moduleSignatures[_syntaxTree.Metadata.ModuleName];
|
var module = _importedModules[_syntaxTree.Metadata.ModuleName];
|
||||||
if (module.AllFunctions.TryGetValue(expression.Name, out var function))
|
var function = module.AllFunctions.FirstOrDefault(x => x.Name == expression.Name);
|
||||||
|
|
||||||
|
if (function != null)
|
||||||
{
|
{
|
||||||
return new FuncIdentifierNode(function, _syntaxTree.Metadata.ModuleName, expression.Name);
|
return new FuncIdentifierNode(function.FuncType, _syntaxTree.Metadata.ModuleName, expression.Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new TypeCheckerException(Diagnostic.Error($"Identifier {expression.Name} not found").At(expression).Build());
|
throw new TypeCheckerException(Diagnostic.Error($"Symbol {expression.Name} not found").At(expression).Build());
|
||||||
}
|
}
|
||||||
|
|
||||||
private ExpressionNode CheckModuleIdentifier(ModuleIdentifierSyntax expression)
|
private ExpressionNode CheckModuleIdentifier(ModuleIdentifierSyntax expression)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
if (!_importedModules.TryGetValue(expression.Module, out var module))
|
||||||
|
{
|
||||||
|
throw new TypeCheckerException(Diagnostic.Error($"Module {expression.Module} not found").WithHelp($"import \"{expression.Module}\"").At(expression).Build());
|
||||||
|
}
|
||||||
|
|
||||||
|
// First, look for the exported function in the specified module (or all functions if current module)
|
||||||
|
if (expression.Module == _syntaxTree.Metadata.ModuleName)
|
||||||
|
{
|
||||||
|
var function = module.AllFunctions.FirstOrDefault(x => x.Name == expression.Name);
|
||||||
|
if (function != null)
|
||||||
|
{
|
||||||
|
return new FuncIdentifierNode(function.FuncType, expression.Module, expression.Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var function = module.ExportedFunctions.FirstOrDefault(x => x.Name == expression.Name);
|
||||||
|
if (function != null)
|
||||||
|
{
|
||||||
|
return new FuncIdentifierNode(function.FuncType, expression.Module, expression.Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new TypeCheckerException(Diagnostic.Error($"No exported symbol {expression.Name} not found in module {expression.Module}").At(expression).Build());
|
||||||
}
|
}
|
||||||
|
|
||||||
private LiteralNode CheckLiteral(LiteralSyntax expression, TypeNode? expectedType)
|
private LiteralNode CheckLiteral(LiteralSyntax expression, TypeNode? expectedType)
|
||||||
@@ -406,9 +431,61 @@ public sealed class TypeChecker
|
|||||||
return new BlockNode(statements);
|
return new BlockNode(statements);
|
||||||
}
|
}
|
||||||
|
|
||||||
private TypeNode ResolveType(TypeSyntax fieldType)
|
private TypeNode ResolveType(TypeSyntax type)
|
||||||
{
|
{
|
||||||
return TypeResolver.ResolveType(fieldType, _moduleSignatures);
|
return type switch
|
||||||
|
{
|
||||||
|
BoolTypeSyntax => new BoolTypeNode(),
|
||||||
|
CStringTypeSyntax => new CStringTypeNode(),
|
||||||
|
IntTypeSyntax i => new IntTypeNode(i.Signed, i.Width),
|
||||||
|
CustomTypeSyntax c => ResolveCustomType(c),
|
||||||
|
FloatTypeSyntax f => new FloatTypeNode(f.Width),
|
||||||
|
FuncTypeSyntax func => new FuncTypeNode(func.Parameters.Select(ResolveType).ToList(), ResolveType(func.ReturnType)),
|
||||||
|
ArrayTypeSyntax arr => new ArrayTypeNode(ResolveType(arr.BaseType)),
|
||||||
|
PointerTypeSyntax ptr => new PointerTypeNode(ResolveType(ptr.BaseType)),
|
||||||
|
StringTypeSyntax => new StringTypeNode(),
|
||||||
|
VoidTypeSyntax => new VoidTypeNode(),
|
||||||
|
_ => throw new NotSupportedException($"Unknown type syntax: {type}")
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private TypeNode ResolveCustomType(CustomTypeSyntax customType)
|
||||||
|
{
|
||||||
|
if (!_importedModules.TryGetValue(customType.Module, out var module))
|
||||||
|
{
|
||||||
|
throw new Exception("Module not found: " + customType.Module);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (customType.Module == _syntaxTree.Metadata.ModuleName)
|
||||||
|
{
|
||||||
|
var structType = module.AllStructTypes.FirstOrDefault(x => x.StructType.Name == customType.Name);
|
||||||
|
if (structType != null)
|
||||||
|
{
|
||||||
|
return structType.StructType;
|
||||||
|
}
|
||||||
|
|
||||||
|
var interfaceType = module.AllInterfaceTypes.FirstOrDefault(x => x.InterfaceType.Name == customType.Name);
|
||||||
|
if (interfaceType != null)
|
||||||
|
{
|
||||||
|
return interfaceType.InterfaceType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var structType = module.ExportedStructTypes.FirstOrDefault(x => x.StructType.Name == customType.Name);
|
||||||
|
if (structType != null)
|
||||||
|
{
|
||||||
|
return structType.StructType;
|
||||||
|
}
|
||||||
|
|
||||||
|
var interfaceType = module.ExportedInterfaceTypes.FirstOrDefault(x => x.InterfaceType.Name == customType.Name);
|
||||||
|
if (interfaceType != null)
|
||||||
|
{
|
||||||
|
return interfaceType.InterfaceType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new TypeCheckerException(Diagnostic.Error($"Type {customType.Name} not found in module {customType.Module}").At(customType).Build());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,95 +0,0 @@
|
|||||||
using NubLang.Parsing.Syntax;
|
|
||||||
using NubLang.TypeChecking;
|
|
||||||
using NubLang.TypeChecking.Node;
|
|
||||||
|
|
||||||
namespace NubLang;
|
|
||||||
|
|
||||||
public static class TypeResolver
|
|
||||||
{
|
|
||||||
public static TypeNode ResolveType(TypeSyntax type, IReadOnlyDictionary<string, ModuleSignature> modules)
|
|
||||||
{
|
|
||||||
return type switch
|
|
||||||
{
|
|
||||||
BoolTypeSyntax => new BoolTypeNode(),
|
|
||||||
CStringTypeSyntax => new CStringTypeNode(),
|
|
||||||
IntTypeSyntax i => new IntTypeNode(i.Signed, i.Width),
|
|
||||||
CustomTypeSyntax c => ResolveCustomType(c.Module, c.Name, modules),
|
|
||||||
FloatTypeSyntax f => new FloatTypeNode(f.Width),
|
|
||||||
FuncTypeSyntax func => new FuncTypeNode(func.Parameters.Select(x => ResolveType(x, modules)).ToList(), ResolveType(func.ReturnType, modules)),
|
|
||||||
ArrayTypeSyntax arr => new ArrayTypeNode(ResolveType(arr.BaseType, modules)),
|
|
||||||
PointerTypeSyntax ptr => new PointerTypeNode(ResolveType(ptr.BaseType, modules)),
|
|
||||||
StringTypeSyntax => new StringTypeNode(),
|
|
||||||
VoidTypeSyntax => new VoidTypeNode(),
|
|
||||||
_ => throw new NotSupportedException($"Unknown type syntax: {type}")
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static TypeNode ResolveCustomType(string moduleName, string typeName, IReadOnlyDictionary<string, ModuleSignature> modules)
|
|
||||||
{
|
|
||||||
if (!modules.TryGetValue(moduleName, out var module))
|
|
||||||
{
|
|
||||||
throw new Exception("Module not found: " + moduleName);
|
|
||||||
}
|
|
||||||
|
|
||||||
var structType = module.AllStructTypes.FirstOrDefault(x => x.Name == typeName);
|
|
||||||
if (structType != null)
|
|
||||||
{
|
|
||||||
return structType;
|
|
||||||
}
|
|
||||||
|
|
||||||
var interfaceType = module.AllInterfaceTypes.FirstOrDefault(x => x.Name == typeName);
|
|
||||||
if (interfaceType != null)
|
|
||||||
{
|
|
||||||
return interfaceType;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Exception($"Type {typeName} not found in module {moduleName}");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static StructTypeNode ResolveStructType(string moduleName, string structName, IReadOnlyDictionary<string, ModuleSignature> modules)
|
|
||||||
{
|
|
||||||
if (!modules.TryGetValue(moduleName, out var module))
|
|
||||||
{
|
|
||||||
throw new Exception("Module not found: " + moduleName);
|
|
||||||
}
|
|
||||||
|
|
||||||
var structType = module.AllStructTypes.FirstOrDefault(x => x.Name == structName);
|
|
||||||
if (structType != null)
|
|
||||||
{
|
|
||||||
return structType;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Exception($"Struct type {structName} not found in module {moduleName}");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static InterfaceTypeNode ResolveInterfaceType(string moduleName, string interfaceName, IReadOnlyDictionary<string, ModuleSignature> modules)
|
|
||||||
{
|
|
||||||
if (!modules.TryGetValue(moduleName, out var module))
|
|
||||||
{
|
|
||||||
throw new Exception("Module not found: " + moduleName);
|
|
||||||
}
|
|
||||||
|
|
||||||
var structType = module.AllInterfaceTypes.FirstOrDefault(x => x.Name == interfaceName);
|
|
||||||
if (structType != null)
|
|
||||||
{
|
|
||||||
return structType;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Exception($"Interface type {interfaceName} not found in module {moduleName}");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static FuncTypeNode ResolveFunctionType(string moduleName, string funcName, IReadOnlyDictionary<string, ModuleSignature> modules)
|
|
||||||
{
|
|
||||||
if (!modules.TryGetValue(moduleName, out var module))
|
|
||||||
{
|
|
||||||
throw new Exception("Module not found: " + moduleName);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (module.AllFunctions.TryGetValue(funcName, out var funcType))
|
|
||||||
{
|
|
||||||
return funcType;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Exception($"Function type {funcName} not found in module {moduleName}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +1,20 @@
|
|||||||
module "main"
|
module "main"
|
||||||
|
import "test"
|
||||||
|
|
||||||
extern "puts" func puts(text: cstring)
|
export extern "puts" func puts(text: cstring)
|
||||||
|
|
||||||
|
struct Human
|
||||||
|
{
|
||||||
|
name: cstring
|
||||||
|
age: u64
|
||||||
|
}
|
||||||
|
|
||||||
func main(args: []cstring): i64
|
func main(args: []cstring): i64
|
||||||
{
|
{
|
||||||
puts("test")
|
let me: main::Human = {
|
||||||
|
name = "Oliver"
|
||||||
|
age = 21
|
||||||
|
}
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ out: .build/out.o
|
|||||||
gcc -nostartfiles -o out x86_64.s .build/out.o
|
gcc -nostartfiles -o out x86_64.s .build/out.o
|
||||||
|
|
||||||
.build/out.o: $(NUBC) main.nub
|
.build/out.o: $(NUBC) main.nub
|
||||||
$(NUBC) main.nub module.nub
|
$(NUBC) main.nub
|
||||||
|
|
||||||
.PHONY: $(NUBC)
|
.PHONY: $(NUBC)
|
||||||
$(NUBC):
|
$(NUBC):
|
||||||
|
|||||||
Reference in New Issue
Block a user