diff --git a/compiler/NubLang.CLI/Program.cs b/compiler/NubLang.CLI/Program.cs index bd824c7..e458b77 100644 --- a/compiler/NubLang.CLI/Program.cs +++ b/compiler/NubLang.CLI/Program.cs @@ -60,7 +60,7 @@ foreach (var file in options.Files) syntaxTrees.Add(syntaxTree); } -var moduleSignatures = ModuleSignature.CollectFromSyntaxTrees(syntaxTrees); +var moduleSignatures = Module.CollectFromSyntaxTrees(syntaxTrees); var definitions = new List(); diff --git a/compiler/NubLang/Code/SourceLocation.cs b/compiler/NubLang/Code/SourceLocation.cs index 38bf900..a39f0f8 100644 --- a/compiler/NubLang/Code/SourceLocation.cs +++ b/compiler/NubLang/Code/SourceLocation.cs @@ -1,6 +1,6 @@ namespace NubLang.Code; -public readonly struct SourceLocation : IEquatable +public readonly struct SourceLocation : IEquatable, IComparable { public static SourceLocation Zero => new(0, 0); @@ -39,4 +39,10 @@ public readonly struct SourceLocation : IEquatable 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); + } } \ No newline at end of file diff --git a/compiler/NubLang/Code/SourceSpan.cs b/compiler/NubLang/Code/SourceSpan.cs index 3e7a89b..cc5e320 100644 --- a/compiler/NubLang/Code/SourceSpan.cs +++ b/compiler/NubLang/Code/SourceSpan.cs @@ -1,6 +1,6 @@ namespace NubLang.Code; -public readonly struct SourceSpan : IEquatable +public readonly struct SourceSpan : IEquatable, IComparable { public static SourceSpan Zero => new(SourceLocation.Zero, SourceLocation.Zero); @@ -54,4 +54,15 @@ public readonly struct SourceSpan : IEquatable 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); + } } \ No newline at end of file diff --git a/compiler/NubLang/Diagnostics/Diagnostic.cs b/compiler/NubLang/Diagnostics/Diagnostic.cs index b1fdd5f..dd9da68 100644 --- a/compiler/NubLang/Diagnostics/Diagnostic.cs +++ b/compiler/NubLang/Diagnostics/Diagnostic.cs @@ -27,7 +27,7 @@ public class Diagnostic var first = node.Tokens.FirstOrDefault(); 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)); } } diff --git a/compiler/NubLang/Generation/QBE/QBEGenerator.cs b/compiler/NubLang/Generation/QBE/QBEGenerator.cs index 643495f..f9c6b53 100644 --- a/compiler/NubLang/Generation/QBE/QBEGenerator.cs +++ b/compiler/NubLang/Generation/QBE/QBEGenerator.cs @@ -11,7 +11,7 @@ public class QBEGenerator { private readonly QBEWriter _writer; private readonly IReadOnlyList _definitions; - private readonly IReadOnlyDictionary _moduleSignatures; + private readonly IReadOnlyDictionary _moduleSignatures; private readonly List _cStringLiterals = []; private readonly List _stringLiterals = []; @@ -23,7 +23,7 @@ public class QBEGenerator private int _stringLiteralIndex; private bool _codeIsReachable = true; - public QBEGenerator(IReadOnlyList definitions, IReadOnlyDictionary moduleSignatures) + public QBEGenerator(IReadOnlyList definitions, IReadOnlyDictionary moduleSignatures) { _definitions = definitions; _moduleSignatures = moduleSignatures; @@ -46,7 +46,7 @@ public class QBEGenerator { foreach (var structType in signature.ExportedStructTypes) { - EmitStructType(module, structType); + EmitStructType(module, structType.StructType); _writer.NewLine(); } } @@ -410,8 +410,6 @@ public class QBEGenerator 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("@start"); // _writer.Indented($"%struct =l alloc8 {SizeOf(type)}"); @@ -660,7 +658,6 @@ public class QBEGenerator private string EmitFuncIdentifier(FuncIdentifierNode funcIdent) { - // todo(nub31): Support for extern funcs return FuncName(funcIdent.Module, funcIdent.Name); } @@ -755,9 +752,7 @@ public class QBEGenerator private string EmitAddressOfStructFieldAccess(StructFieldAccessNode structFieldAccess) { var target = EmitExpression(structFieldAccess.Target); - - var structType = TypeResolver.ResolveStructType(structFieldAccess.StructType.Module, structFieldAccess.StructType.Name, _moduleSignatures); - var offset = OffsetOf(structType, structFieldAccess.Field); + var offset = OffsetOf(structFieldAccess.StructType, structFieldAccess.Field); var address = TmpName(); _writer.Indented($"{address} =l add {target}, {offset}"); @@ -1398,8 +1393,8 @@ public class QBEGenerator private string FuncName(string module, string name) { - var type = TypeResolver.ResolveFunctionType(module, name, _moduleSignatures); - var symbol = type.ExternSymbol ?? $"{module}.{name}"; + var function = _moduleSignatures[module].AllFunctions.First(x => x.Name == name); + var symbol = function.ExternSymbol ?? $"{module}.{name}"; return "$" + symbol; } diff --git a/compiler/NubLang/Parsing/Parser.cs b/compiler/NubLang/Parsing/Parser.cs index 8e6012e..a381540 100644 --- a/compiler/NubLang/Parsing/Parser.cs +++ b/compiler/NubLang/Parsing/Parser.cs @@ -474,7 +474,7 @@ public sealed class Parser var expr = token switch { 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 { Symbol.OpenParen => ParseParenthesizedExpression(), @@ -499,6 +499,17 @@ public sealed class Parser 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() { var expression = ParseExpression(); @@ -690,14 +701,27 @@ public sealed class Parser return new FloatTypeSyntax(GetTokens(startIndex), size); } - return name.Value switch + switch (name.Value) { - "void" => new VoidTypeSyntax(GetTokens(startIndex)), - "string" => new StringTypeSyntax(GetTokens(startIndex)), - "cstring" => new CStringTypeSyntax(GetTokens(startIndex)), - "bool" => new BoolTypeSyntax(GetTokens(startIndex)), - _ => new CustomTypeSyntax(GetTokens(startIndex), _moduleName, name.Value) - }; + case "void": + return new VoidTypeSyntax(GetTokens(startIndex)); + case "string": + return new StringTypeSyntax(GetTokens(startIndex)); + 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)) diff --git a/compiler/NubLang/Parsing/Syntax/TypeSyntax.cs b/compiler/NubLang/Parsing/Syntax/TypeSyntax.cs index 29ff911..8b0ca2d 100644 --- a/compiler/NubLang/Parsing/Syntax/TypeSyntax.cs +++ b/compiler/NubLang/Parsing/Syntax/TypeSyntax.cs @@ -4,7 +4,7 @@ namespace NubLang.Parsing.Syntax; public abstract record TypeSyntax(IEnumerable Tokens) : SyntaxNode(Tokens); -public record FuncTypeSyntax(IEnumerable Tokens, IReadOnlyList Parameters, TypeSyntax ReturnType) : TypeSyntax(Tokens); +public record FuncTypeSyntax(IEnumerable Tokens, IReadOnlyList Parameters, TypeSyntax ReturnType) : TypeSyntax(Tokens); public record PointerTypeSyntax(IEnumerable Tokens, TypeSyntax BaseType) : TypeSyntax(Tokens); diff --git a/compiler/NubLang/Tokenization/Token.cs b/compiler/NubLang/Tokenization/Token.cs index f5ec1cd..50eb69d 100644 --- a/compiler/NubLang/Tokenization/Token.cs +++ b/compiler/NubLang/Tokenization/Token.cs @@ -41,6 +41,7 @@ public enum Symbol Break, Continue, Colon, + DoubleColon, OpenParen, CloseParen, OpenBrace, diff --git a/compiler/NubLang/Tokenization/Tokenizer.cs b/compiler/NubLang/Tokenization/Tokenizer.cs index c629bf9..9aeb2d9 100644 --- a/compiler/NubLang/Tokenization/Tokenizer.cs +++ b/compiler/NubLang/Tokenization/Tokenizer.cs @@ -35,6 +35,7 @@ public sealed class Tokenizer [['>', '>']] = Symbol.RightShift, [['&', '&']] = Symbol.And, [['|', '|']] = Symbol.Or, + [[':', ':']] = Symbol.DoubleColon, [[':']] = Symbol.Colon, [['(']] = Symbol.OpenParen, [[')']] = Symbol.CloseParen, diff --git a/compiler/NubLang/TypeChecking/Module.cs b/compiler/NubLang/TypeChecking/Module.cs index cb4bc50..c5cb328 100644 --- a/compiler/NubLang/TypeChecking/Module.cs +++ b/compiler/NubLang/TypeChecking/Module.cs @@ -3,11 +3,11 @@ using NubLang.TypeChecking.Node; namespace NubLang.TypeChecking; -public class ModuleSignature +public class Module { - public static IReadOnlyDictionary CollectFromSyntaxTrees(IReadOnlyList syntaxTrees) + public static IReadOnlyDictionary CollectFromSyntaxTrees(IReadOnlyList syntaxTrees) { - var modules = new Dictionary(); + var modules = new Dictionary(); foreach (var syntaxTree in syntaxTrees) { @@ -15,7 +15,7 @@ public class ModuleSignature if (!modules.TryGetValue(moduleName, out var module)) { - module = new ModuleSignature(); + module = new Module(); modules[moduleName] = module; } @@ -25,11 +25,11 @@ public class ModuleSignature { case FuncSyntax funcDef: { - var parameters = funcDef.Signature.Parameters.Select(p => TypeResolver.ResolveType(p.Type, modules)).ToList(); - var returnType = TypeResolver.ResolveType(funcDef.Signature.ReturnType, modules); + var parameters = funcDef.Signature.Parameters.Select(p => ResolveType(p.Type)).ToList(); + var returnType = ResolveType(funcDef.Signature.ReturnType); - var type = new FuncTypeNode(parameters, returnType, funcDef.ExternSymbol); - module._functions.Add(funcDef.Name, new ModuleMember(type, def.Exported)); + var type = new FuncTypeNode(parameters, returnType); + module._functions.Add(new ModuleFuncType(def.Exported, funcDef.Name, funcDef.ExternSymbol, type)); break; } case InterfaceSyntax interfaceDef: @@ -38,13 +38,13 @@ public class ModuleSignature for (var i = 0; i < interfaceDef.Functions.Count; i++) { var function = interfaceDef.Functions[i]; - var parameters = function.Signature.Parameters.Select(p => TypeResolver.ResolveType(p.Type, modules)).ToList(); - var returnType = TypeResolver.ResolveType(function.Signature.ReturnType, modules); + var parameters = function.Signature.Parameters.Select(p => ResolveType(p.Type)).ToList(); + var returnType = ResolveType(function.Signature.ReturnType); functions.Add(new InterfaceTypeFunc(function.Name, new FuncTypeNode(parameters, returnType), i)); } var type = new InterfaceTypeNode(moduleName, interfaceDef.Name, functions); - module._interfaces.Add(new ModuleMember(type, def.Exported)); + module._interfaces.Add(new ModuleInterfaceType(def.Exported, type)); break; } case StructSyntax structDef: @@ -52,14 +52,14 @@ public class ModuleSignature var fields = new List(); 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(); foreach (var function in structDef.Functions) { - var parameters = function.Signature.Parameters.Select(p => TypeResolver.ResolveType(p.Type, modules)).ToList(); - var returnType = TypeResolver.ResolveType(function.Signature.ReturnType, modules); + var parameters = function.Signature.Parameters.Select(p => ResolveType(p.Type)).ToList(); + var returnType = ResolveType(function.Signature.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"); } - var resolvedType = TypeResolver.ResolveCustomType(customType.Module, customType.Name, modules); + var resolvedType = ResolveType(customType); if (resolvedType is not InterfaceTypeNode interfaceType) { 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); - module._structs.Add(new ModuleMember(type, def.Exported)); + module._structs.Add(new ModuleStructType(def.Exported, type)); break; } default: @@ -93,29 +93,97 @@ public class ModuleSignature } return modules; - } - private class ModuleMember - { - public ModuleMember(T value, bool exported) + TypeNode ResolveType(TypeSyntax type) { - Value = value; - Exported = exported; + 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}") + }; } - public T Value { get; set; } - public bool Exported { get; set; } + TypeNode ResolveCustomType(string moduleName, string typeName) + { + 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> _structs = []; - private readonly List> _interfaces = []; - private readonly Dictionary> _functions = []; + private readonly List _structs = []; + private readonly List _interfaces = []; + private readonly List _functions = []; - public IReadOnlyList ExportedStructTypes => _structs.Where(x => x.Exported).Select(x => x.Value).ToList(); - public IReadOnlyList ExportedInterfaceTypes => _interfaces.Where(x => x.Exported).Select(x => x.Value).ToList(); - public IReadOnlyDictionary ExportedFunctions => _functions.Where(x => x.Value.Exported).ToDictionary(x => x.Key, x => x.Value.Value); + public IReadOnlyList ExportedStructTypes => _structs.Where(x => x.Exported).ToList(); + public IReadOnlyList ExportedInterfaceTypes => _interfaces.Where(x => x.Exported).ToList(); + public IReadOnlyList ExportedFunctions => _functions.Where(x => x.Exported).ToList(); - public IReadOnlyList AllStructTypes => _structs.Select(x => x.Value).ToList(); - public IReadOnlyList AllInterfaceTypes => _interfaces.Select(x => x.Value).ToList(); - public IReadOnlyDictionary AllFunctions => _functions.ToDictionary(x => x.Key, x => x.Value.Value); + public IReadOnlyList AllStructTypes => _structs; + public IReadOnlyList AllInterfaceTypes => _interfaces; + public IReadOnlyList AllFunctions => _functions; +} + +public class ModuleStructType +{ + public ModuleStructType(bool exported, StructTypeNode structType) + { + Exported = exported; + StructType = structType; + } + + public bool Exported { get; } + public StructTypeNode StructType { get; } +} + +public class ModuleInterfaceType +{ + public ModuleInterfaceType(bool exported, InterfaceTypeNode interfaceType) + { + Exported = exported; + InterfaceType = interfaceType; + } + + public bool Exported { get; } + public InterfaceTypeNode InterfaceType { get; } +} + +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; } } \ No newline at end of file diff --git a/compiler/NubLang/TypeChecking/Node/TypeNode.cs b/compiler/NubLang/TypeChecking/Node/TypeNode.cs index 121d533..55d29aa 100644 --- a/compiler/NubLang/TypeChecking/Node/TypeNode.cs +++ b/compiler/NubLang/TypeChecking/Node/TypeNode.cs @@ -110,9 +110,8 @@ public class BoolTypeNode : SimpleTypeNode public override int GetHashCode() => HashCode.Combine(typeof(BoolTypeNode)); } -public class FuncTypeNode(IReadOnlyList parameters, TypeNode returnType, string? externSymbol = null) : SimpleTypeNode +public class FuncTypeNode(IReadOnlyList parameters, TypeNode returnType) : SimpleTypeNode { - public string? ExternSymbol { get; } = externSymbol; public IReadOnlyList Parameters { get; } = parameters; public TypeNode ReturnType { get; } = returnType; diff --git a/compiler/NubLang/TypeChecking/TypeChecker.cs b/compiler/NubLang/TypeChecking/TypeChecker.cs index 8681652..0f0e4a3 100644 --- a/compiler/NubLang/TypeChecking/TypeChecker.cs +++ b/compiler/NubLang/TypeChecking/TypeChecker.cs @@ -8,7 +8,7 @@ namespace NubLang.TypeChecking; public sealed class TypeChecker { private readonly SyntaxTree _syntaxTree; - private readonly IReadOnlyDictionary _moduleSignatures; + private readonly IReadOnlyDictionary _importedModules; private readonly Stack _scopes = []; private readonly Stack _funcReturnTypes = []; @@ -16,10 +16,10 @@ public sealed class TypeChecker private Scope Scope => _scopes.Peek(); - public TypeChecker(SyntaxTree syntaxTree, IReadOnlyDictionary moduleSignatures) + public TypeChecker(SyntaxTree syntaxTree, IReadOnlyDictionary moduleSignatures) { _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 GetDiagnostics() => _diagnostics; @@ -346,18 +346,43 @@ public sealed class TypeChecker } // Second, look in the current module for a function matching the identifier - var module = _moduleSignatures[_syntaxTree.Metadata.ModuleName]; - if (module.AllFunctions.TryGetValue(expression.Name, out var function)) + var module = _importedModules[_syntaxTree.Metadata.ModuleName]; + 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) { - 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) @@ -406,9 +431,61 @@ public sealed class TypeChecker 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()); } } diff --git a/compiler/NubLang/TypeResolver.cs b/compiler/NubLang/TypeResolver.cs deleted file mode 100644 index d457da4..0000000 --- a/compiler/NubLang/TypeResolver.cs +++ /dev/null @@ -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 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 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 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 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 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}"); - } -} \ No newline at end of file diff --git a/example/main.nub b/example/main.nub index 5e82dfc..d49e124 100644 --- a/example/main.nub +++ b/example/main.nub @@ -1,9 +1,20 @@ 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 { - puts("test") + let me: main::Human = { + name = "Oliver" + age = 21 + } + return 0 } diff --git a/example/makefile b/example/makefile index c159d03..d2eebc9 100644 --- a/example/makefile +++ b/example/makefile @@ -4,7 +4,7 @@ out: .build/out.o gcc -nostartfiles -o out x86_64.s .build/out.o .build/out.o: $(NUBC) main.nub - $(NUBC) main.nub module.nub + $(NUBC) main.nub .PHONY: $(NUBC) $(NUBC):