This commit is contained in:
nub31
2025-10-31 15:18:18 +01:00
parent 7c7624b1bc
commit 40d500fddd
8 changed files with 231 additions and 188 deletions

View File

@@ -7,13 +7,15 @@ using NubLang.Syntax;
var diagnostics = new List<Diagnostic>(); var diagnostics = new List<Diagnostic>();
var syntaxTrees = new List<SyntaxTree>(); var syntaxTrees = new List<SyntaxTree>();
var tokenizer = new Tokenizer();
var parser = new Parser();
var generator = new LlvmGenerator();
foreach (var file in args) foreach (var file in args)
{ {
var tokenizer = new Tokenizer(file, File.ReadAllText(file)); tokenizer.Tokenize(file, File.ReadAllText(file));
tokenizer.Tokenize();
diagnostics.AddRange(tokenizer.Diagnostics); diagnostics.AddRange(tokenizer.Diagnostics);
var parser = new Parser();
var syntaxTree = parser.Parse(tokenizer.Tokens); var syntaxTree = parser.Parse(tokenizer.Tokens);
diagnostics.AddRange(parser.Diagnostics); diagnostics.AddRange(parser.Diagnostics);
@@ -60,7 +62,6 @@ for (var i = 0; i < args.Length; i++)
var file = args[i]; var file = args[i];
var compilationUnit = compilationUnits[i]; var compilationUnit = compilationUnits[i];
var generator = new LlvmGenerator();
var directory = Path.GetDirectoryName(file); var directory = Path.GetDirectoryName(file);
if (!string.IsNullOrWhiteSpace(directory)) if (!string.IsNullOrWhiteSpace(directory))
{ {

View File

@@ -55,21 +55,6 @@ internal class DefinitionHandler(WorkspaceManager workspaceManager) : Definition
return null; return null;
} }
case ModuleFuncIdentifierNode funcIdentifierNode:
{
// var prototype = compilationUnit
// .ImportedFunctions
// .Where(x => x.Key.Value == funcIdentifierNode.ModuleToken.Value)
// .SelectMany(x => x.Value)
// .FirstOrDefault(x => x.NameToken.Value == funcIdentifierNode.NameToken.Value);
//
// if (prototype != null)
// {
// return new LocationOrLocationLinks(prototype.ToLocation());
// }
return null;
}
default: default:
{ {
return null; return null;

View File

@@ -1,5 +1,7 @@
using System.Globalization; using System.Globalization;
using NubLang.Ast; using NubLang.Ast;
using NubLang.Modules;
using NubLang.Types;
using OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities; using OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities;
using OmniSharp.Extensions.LanguageServer.Protocol.Document; using OmniSharp.Extensions.LanguageServer.Protocol.Document;
using OmniSharp.Extensions.LanguageServer.Protocol.Models; using OmniSharp.Extensions.LanguageServer.Protocol.Models;
@@ -29,6 +31,23 @@ internal class HoverHandler(WorkspaceManager workspaceManager) : HoverHandlerBas
return null; return null;
} }
var moduleDecl = compilationUnit.OfType<ModuleNode>().FirstOrDefault();
if (moduleDecl == null)
{
return null;
}
var moduleRepository = workspaceManager.GetModuleRepository();
if (moduleRepository == null)
{
return null;
}
if (!moduleRepository.TryGet(moduleDecl.NameToken, out var module))
{
return null;
}
var line = request.Position.Line; var line = request.Position.Line;
var character = request.Position.Character; var character = request.Position.Character;
@@ -39,110 +58,119 @@ internal class HoverHandler(WorkspaceManager workspaceManager) : HoverHandlerBas
return null; return null;
} }
// var message = CreateMessage(hoveredNode, compilationUnit); var message = CreateMessage(hoveredNode, moduleRepository, module);
// if (message == null) if (message == null)
// { {
// return null;
// }
//
// return new Hover
// {
// Contents = new MarkedStringsOrMarkupContent(new MarkupContent
// {
// Value = message,
// Kind = MarkupKind.Markdown,
// })
// };
return null; return null;
} }
// private static string? CreateMessage(Node hoveredNode, CompilationUnit compilationUnit) return new Hover
// { {
// return hoveredNode switch Contents = new MarkedStringsOrMarkupContent(new MarkupContent
// { {
// FuncNode funcNode => CreateFuncPrototypeMessage(funcNode.Prototype), Value = message,
// FuncPrototypeNode funcPrototypeNode => CreateFuncPrototypeMessage(funcPrototypeNode), Kind = MarkupKind.Markdown,
// FuncIdentifierNode funcIdentifierNode => CreateFuncIdentifierMessage(funcIdentifierNode, compilationUnit), })
// FuncParameterNode funcParameterNode => CreateTypeNameMessage("Function parameter", funcParameterNode.NameToken.Value, funcParameterNode.Type), };
// VariableIdentifierNode variableIdentifierNode => CreateTypeNameMessage("Variable", variableIdentifierNode.NameToken.Value, variableIdentifierNode.Type), }
// VariableDeclarationNode variableDeclarationNode => CreateTypeNameMessage("Variable declaration", variableDeclarationNode.NameToken.Value, variableDeclarationNode.Type),
// StructFieldAccessNode structFieldAccessNode => CreateTypeNameMessage("Struct field", $"{structFieldAccessNode.Target.Type}.{structFieldAccessNode.FieldToken.Value}", structFieldAccessNode.Type), private static string? CreateMessage(Node hoveredNode, ModuleRepository repository, ModuleRepository.Module currentModule)
// CStringLiteralNode cStringLiteralNode => CreateLiteralMessage(cStringLiteralNode.Type, '"' + cStringLiteralNode.Value + '"'), {
// StringLiteralNode stringLiteralNode => CreateLiteralMessage(stringLiteralNode.Type, '"' + stringLiteralNode.Value + '"'), return hoveredNode switch
// BoolLiteralNode boolLiteralNode => CreateLiteralMessage(boolLiteralNode.Type, boolLiteralNode.Value.ToString()), {
// Float32LiteralNode float32LiteralNode => CreateLiteralMessage(float32LiteralNode.Type, float32LiteralNode.Value.ToString(CultureInfo.InvariantCulture)), FuncNode funcNode => CreateFuncPrototypeMessage(funcNode.Prototype),
// Float64LiteralNode float64LiteralNode => CreateLiteralMessage(float64LiteralNode.Type, float64LiteralNode.Value.ToString(CultureInfo.InvariantCulture)), FuncPrototypeNode funcPrototypeNode => CreateFuncPrototypeMessage(funcPrototypeNode),
// I8LiteralNode i8LiteralNode => CreateLiteralMessage(i8LiteralNode.Type, i8LiteralNode.Value.ToString()), LocalFuncIdentifierNode funcIdentifierNode => CreateLocalFuncIdentifierMessage(funcIdentifierNode, currentModule),
// I16LiteralNode i16LiteralNode => CreateLiteralMessage(i16LiteralNode.Type, i16LiteralNode.Value.ToString()), ModuleFuncIdentifierNode funcIdentifierNode => CreateModuleFuncIdentifierMessage(funcIdentifierNode, repository),
// I32LiteralNode i32LiteralNode => CreateLiteralMessage(i32LiteralNode.Type, i32LiteralNode.Value.ToString()), FuncParameterNode funcParameterNode => CreateTypeNameMessage("Function parameter", funcParameterNode.NameToken.Value, funcParameterNode.Type),
// I64LiteralNode i64LiteralNode => CreateLiteralMessage(i64LiteralNode.Type, i64LiteralNode.Value.ToString()), VariableIdentifierNode variableIdentifierNode => CreateTypeNameMessage("Variable", variableIdentifierNode.NameToken.Value, variableIdentifierNode.Type),
// U8LiteralNode u8LiteralNode => CreateLiteralMessage(u8LiteralNode.Type, u8LiteralNode.Value.ToString()), VariableDeclarationNode variableDeclarationNode => CreateTypeNameMessage("Variable declaration", variableDeclarationNode.NameToken.Value, variableDeclarationNode.Type),
// U16LiteralNode u16LiteralNode => CreateLiteralMessage(u16LiteralNode.Type, u16LiteralNode.Value.ToString()), StructFieldAccessNode structFieldAccessNode => CreateTypeNameMessage("Struct field", $"{structFieldAccessNode.Target.Type}.{structFieldAccessNode.FieldToken.Value}", structFieldAccessNode.Type),
// U32LiteralNode u32LiteralNode => CreateLiteralMessage(u32LiteralNode.Type, u32LiteralNode.Value.ToString()), CStringLiteralNode cStringLiteralNode => CreateLiteralMessage(cStringLiteralNode.Type, '"' + cStringLiteralNode.Value + '"'),
// U64LiteralNode u64LiteralNode => CreateLiteralMessage(u64LiteralNode.Type, u64LiteralNode.Value.ToString()), StringLiteralNode stringLiteralNode => CreateLiteralMessage(stringLiteralNode.Type, '"' + stringLiteralNode.Value + '"'),
// // Expressions can have a generic fallback showing the resulting type BoolLiteralNode boolLiteralNode => CreateLiteralMessage(boolLiteralNode.Type, boolLiteralNode.Value.ToString()),
// ExpressionNode expressionNode => $""" Float32LiteralNode float32LiteralNode => CreateLiteralMessage(float32LiteralNode.Type, float32LiteralNode.Value.ToString(CultureInfo.InvariantCulture)),
// **Expression** `{expressionNode.GetType().Name}` Float64LiteralNode float64LiteralNode => CreateLiteralMessage(float64LiteralNode.Type, float64LiteralNode.Value.ToString(CultureInfo.InvariantCulture)),
// ```nub I8LiteralNode i8LiteralNode => CreateLiteralMessage(i8LiteralNode.Type, i8LiteralNode.Value.ToString()),
// {expressionNode.Type} I16LiteralNode i16LiteralNode => CreateLiteralMessage(i16LiteralNode.Type, i16LiteralNode.Value.ToString()),
// ``` I32LiteralNode i32LiteralNode => CreateLiteralMessage(i32LiteralNode.Type, i32LiteralNode.Value.ToString()),
// """, I64LiteralNode i64LiteralNode => CreateLiteralMessage(i64LiteralNode.Type, i64LiteralNode.Value.ToString()),
// BlockNode => null, U8LiteralNode u8LiteralNode => CreateLiteralMessage(u8LiteralNode.Type, u8LiteralNode.Value.ToString()),
// _ => hoveredNode.GetType().Name U16LiteralNode u16LiteralNode => CreateLiteralMessage(u16LiteralNode.Type, u16LiteralNode.Value.ToString()),
// }; U32LiteralNode u32LiteralNode => CreateLiteralMessage(u32LiteralNode.Type, u32LiteralNode.Value.ToString()),
// } U64LiteralNode u64LiteralNode => CreateLiteralMessage(u64LiteralNode.Type, u64LiteralNode.Value.ToString()),
// // Expressions can have a generic fallback showing the resulting type
// private static string CreateLiteralMessage(NubType type, string value) ExpressionNode expressionNode => $"""
// { **Expression** `{expressionNode.GetType().Name}`
// return $""" ```nub
// **Literal** `{type}` {expressionNode.Type}
// ```nub ```
// {value}: {type} """,
// ``` BlockNode => null,
// """; _ => hoveredNode.GetType().Name
// } };
// }
// private static string CreateTypeNameMessage(string description, string name, NubType type)
// { private static string CreateLiteralMessage(NubType type, string value)
// return $""" {
// **{description}** `{name}` return $"""
// ```nub **Literal** `{type}`
// {name}: {type} ```nub
// ``` {value}: {type}
// """; ```
// } """;
// }
// private static string CreateFuncIdentifierMessage(FuncIdentifierNode funcIdentifierNode, CompilationUnit compilationUnit)
// { private static string CreateTypeNameMessage(string description, string name, NubType type)
// var func = compilationUnit.ImportedFunctions {
// .Where(x => x.Key.Value == funcIdentifierNode.ModuleToken.Value) return $"""
// .SelectMany(x => x.Value) **{description}** `{name}`
// .FirstOrDefault(x => x.NameToken.Value == funcIdentifierNode.NameToken.Value); ```nub
// {name}: {type}
// if (func == null) ```
// { """;
// return $""" }
// **Function** `{funcIdentifierNode.ModuleToken.Value}::{funcIdentifierNode.NameToken.Value}`
// ```nub private static string CreateLocalFuncIdentifierMessage(LocalFuncIdentifierNode funcIdentifierNode, ModuleRepository.Module currentModule)
// // Declaration not found {
// ``` if (!currentModule.TryResolveFunc(funcIdentifierNode.NameToken, out var func, out _))
// """; {
// } return $"""
// **Function** `{funcIdentifierNode.NameToken.Value}`
// return CreateFuncPrototypeMessage(func); ```nub
// } // Declaration not found
// ```
// private static string CreateFuncPrototypeMessage(FuncPrototypeNode funcPrototypeNode) """;
// { }
// var parameterText = string.Join(", ", funcPrototypeNode.Parameters.Select(x => $"{x.NameToken.Value}: {x.Type}"));
// var externText = funcPrototypeNode.ExternSymbolToken != null ? $"extern \"{funcPrototypeNode.ExternSymbolToken.Value}\" " : ""; return CreateFuncPrototypeMessage(func);
// }
// return $"""
// **Function** `{funcPrototypeNode.NameToken.Value}` private static string CreateModuleFuncIdentifierMessage(ModuleFuncIdentifierNode funcIdentifierNode, ModuleRepository repository)
// ```nub {
// {externText}func {funcPrototypeNode.NameToken.Value}({parameterText}): {funcPrototypeNode.ReturnType} if (!repository.TryGet(funcIdentifierNode.ModuleToken, out var module) || !module.TryResolveFunc(funcIdentifierNode.NameToken, out var func, out _))
// ``` {
// """; return $"""
// } **Function** `{funcIdentifierNode.ModuleToken.Value}::{funcIdentifierNode.NameToken.Value}`
```nub
// Declaration not found
```
""";
}
return CreateFuncPrototypeMessage(func);
}
private static string CreateFuncPrototypeMessage(FuncPrototypeNode funcPrototypeNode)
{
var parameterText = string.Join(", ", funcPrototypeNode.Parameters.Select(x => $"{x.NameToken.Value}: {x.Type}"));
var externText = funcPrototypeNode.ExternSymbolToken != null ? $"extern \"{funcPrototypeNode.ExternSymbolToken.Value}\" " : "";
return $"""
**Function** `{funcPrototypeNode.NameToken.Value}`
```nub
{externText}func {funcPrototypeNode.NameToken.Value}({parameterText}): {funcPrototypeNode.ReturnType}
```
""";
}
} }

View File

@@ -1,4 +1,6 @@
using NubLang.Ast; using NubLang.Ast;
using NubLang.Diagnostics;
using NubLang.Modules;
using NubLang.Syntax; using NubLang.Syntax;
using OmniSharp.Extensions.LanguageServer.Protocol; using OmniSharp.Extensions.LanguageServer.Protocol;
@@ -8,70 +10,92 @@ public class WorkspaceManager(DiagnosticsPublisher diagnosticsPublisher)
{ {
private readonly Dictionary<string, SyntaxTree> _syntaxTrees = new(); private readonly Dictionary<string, SyntaxTree> _syntaxTrees = new();
private readonly Dictionary<string, List<TopLevelNode>> _compilationUnits = new(); private readonly Dictionary<string, List<TopLevelNode>> _compilationUnits = new();
// private readonly Dictionary<string, TypedModule> _modules = new(); private ModuleRepository? _repository;
public void Init(string rootPath) public void Init(string rootPath)
{ {
// var files = Directory.GetFiles(rootPath, "*.nub", SearchOption.AllDirectories); var files = Directory.GetFiles(rootPath, "*.nub", SearchOption.AllDirectories);
// foreach (var path in files) foreach (var path in files)
// { {
// var text = File.ReadAllText(path); var text = File.ReadAllText(path);
// var tokenizer = new Tokenizer(path, text); var tokenizer = new Tokenizer();
//
// tokenizer.Tokenize(); tokenizer.Tokenize(path, text);
// diagnosticsPublisher.Publish(path, tokenizer.Diagnostics); diagnosticsPublisher.Publish(path, tokenizer.Diagnostics);
//
// var parser = new Parser(); var parser = new Parser();
// var parseResult = parser.Parse(tokenizer.Tokens); var parseResult = parser.Parse(tokenizer.Tokens);
// diagnosticsPublisher.Publish(path, parser.Diagnostics); diagnosticsPublisher.Publish(path, parser.Diagnostics);
//
// _syntaxTrees[path] = parseResult; _syntaxTrees[path] = parseResult;
// } }
//
// foreach (var (fsPath, syntaxTree) in _syntaxTrees) ModuleRepository repository;
// {
// var modules = Module.Collect(_syntaxTrees.Select(x => x.Value).ToList()); foreach (var (fsPath, syntaxTree) in _syntaxTrees)
// {
// var typeChecker = new TypeChecker(syntaxTree, modules); try
// var result = typeChecker.Check(); {
// diagnosticsPublisher.Publish(fsPath, typeChecker.Diagnostics); repository = ModuleRepository.Create(_syntaxTrees.Select(x => x.Value).ToList());
// }
// _compilationUnits[fsPath] = result; catch (CompileException e)
// } {
return;
}
var typeChecker = new TypeChecker();
var result = typeChecker.Check(syntaxTree, repository);
diagnosticsPublisher.Publish(fsPath, typeChecker.Diagnostics);
_compilationUnits[fsPath] = result;
}
} }
public void UpdateFile(DocumentUri path) public void UpdateFile(DocumentUri path)
{ {
// var fsPath = path.GetFileSystemPath(); var fsPath = path.GetFileSystemPath();
//
// var text = File.ReadAllText(fsPath); var text = File.ReadAllText(fsPath);
// var tokenizer = new Tokenizer(fsPath, text); var tokenizer = new Tokenizer();
// tokenizer.Tokenize(); tokenizer.Tokenize(fsPath, text);
// diagnosticsPublisher.Publish(path, tokenizer.Diagnostics); diagnosticsPublisher.Publish(path, tokenizer.Diagnostics);
//
// var parser = new Parser(); var parser = new Parser();
// var syntaxTree = parser.Parse(tokenizer.Tokens); var syntaxTree = parser.Parse(tokenizer.Tokens);
// diagnosticsPublisher.Publish(path, parser.Diagnostics); diagnosticsPublisher.Publish(path, parser.Diagnostics);
// _syntaxTrees[fsPath] = syntaxTree; _syntaxTrees[fsPath] = syntaxTree;
//
// var modules = Module.Collect(_syntaxTrees.Select(x => x.Value).ToList()); ModuleRepository repository;
//
// var typeChecker = new TypeChecker(syntaxTree, modules); try
// var result = typeChecker.Check(); {
// diagnosticsPublisher.Publish(fsPath, typeChecker.Diagnostics); repository = ModuleRepository.Create(_syntaxTrees.Select(x => x.Value).ToList());
// }
// _compilationUnits[fsPath] = result; catch (CompileException e)
{
diagnosticsPublisher.Publish(path, [e.Diagnostic]);
return;
} }
public void RemoveFile(DocumentUri path) var typeChecker = new TypeChecker();
{ var result = typeChecker.Check(syntaxTree, repository);
var fsPath = path.GetFileSystemPath(); diagnosticsPublisher.Publish(fsPath, typeChecker.Diagnostics);
_syntaxTrees.Remove(fsPath); _compilationUnits[fsPath] = result;
_compilationUnits.Remove(fsPath);
} }
public List<TopLevelNode>? GetCompilationUnit(DocumentUri path) public List<TopLevelNode>? GetCompilationUnit(DocumentUri path)
{ {
return _compilationUnits.GetValueOrDefault(path.GetFileSystemPath()); return _compilationUnits.GetValueOrDefault(path.GetFileSystemPath());
} }
public ModuleRepository? GetModuleRepository()
{
try
{
return ModuleRepository.Create(_syntaxTrees.Select(x => x.Value).ToList());
}
catch (CompileException e)
{
return null;
}
}
} }

View File

@@ -105,8 +105,8 @@ public class Diagnostic
sb.AppendLine(); sb.AppendLine();
var text = File.ReadAllText(Span.Value.FilePath); var text = File.ReadAllText(Span.Value.FilePath);
var tokenizer = new Tokenizer(Span.Value.FilePath, text); var tokenizer = new Tokenizer();
tokenizer.Tokenize(); tokenizer.Tokenize(Span.Value.FilePath, text);
var lines = text.Split('\n'); var lines = text.Split('\n');

View File

@@ -161,6 +161,12 @@ public sealed class ModuleRepository
return module; return module;
} }
public bool TryGet(IdentifierToken ident, [NotNullWhen(true)] out Module? module)
{
module = _modules.GetValueOrDefault(ident.Value);
return module != null;
}
public sealed class Module public sealed class Module
{ {
public required string Name { get; init; } public required string Name { get; init; }

View File

@@ -11,14 +11,15 @@ public sealed class Parser
private Token? CurrentToken => _tokenIndex < _tokens.Count ? _tokens[_tokenIndex] : null; private Token? CurrentToken => _tokenIndex < _tokens.Count ? _tokens[_tokenIndex] : null;
private bool HasToken => CurrentToken != null; private bool HasToken => CurrentToken != null;
public List<Diagnostic> Diagnostics { get; } = []; public List<Diagnostic> Diagnostics { get; set; } = [];
public SyntaxTree Parse(List<Token> tokens) public SyntaxTree Parse(List<Token> tokens)
{ {
Diagnostics.Clear();
_tokens = tokens; _tokens = tokens;
_tokenIndex = 0; _tokenIndex = 0;
Diagnostics = [];
var topLevelSyntaxNodes = new List<TopLevelSyntaxNode>(); var topLevelSyntaxNodes = new List<TopLevelSyntaxNode>();
while (HasToken) while (HasToken)

View File

@@ -4,25 +4,23 @@ namespace NubLang.Syntax;
public sealed class Tokenizer public sealed class Tokenizer
{ {
private readonly string _fileName; private string _fileName = null!;
private readonly string _content; private string _content = null!;
private int _index; private int _index;
private int _line = 1; private int _line = 1;
private int _column = 1; private int _column = 1;
public Tokenizer(string fileName, string content) public List<Diagnostic> Diagnostics { get; set; } = new(16);
public List<Token> Tokens { get; set; } = new(256);
public void Tokenize(string fileName, string content)
{ {
_fileName = fileName; _fileName = fileName;
_content = content; _content = content;
}
public List<Diagnostic> Diagnostics { get; } = new(16); Diagnostics = [];
public List<Token> Tokens { get; } = new(256); Tokens = [];
public void Tokenize()
{
Diagnostics.Clear();
Tokens.Clear();
_index = 0; _index = 0;
_line = 1; _line = 1;
_column = 1; _column = 1;