...
This commit is contained in:
@@ -13,10 +13,10 @@ var generator = new LlvmGenerator();
|
|||||||
|
|
||||||
foreach (var file in args)
|
foreach (var file in args)
|
||||||
{
|
{
|
||||||
tokenizer.Tokenize(file, File.ReadAllText(file));
|
var tokens = tokenizer.Tokenize(file, File.ReadAllText(file));
|
||||||
diagnostics.AddRange(tokenizer.Diagnostics);
|
diagnostics.AddRange(tokenizer.Diagnostics);
|
||||||
|
|
||||||
var syntaxTree = parser.Parse(tokenizer.Tokens);
|
var syntaxTree = parser.Parse(tokens);
|
||||||
diagnostics.AddRange(parser.Diagnostics);
|
diagnostics.AddRange(parser.Diagnostics);
|
||||||
|
|
||||||
syntaxTrees.Add(syntaxTree);
|
syntaxTrees.Add(syntaxTree);
|
||||||
@@ -69,7 +69,7 @@ for (var i = 0; i < args.Length; i++)
|
|||||||
}
|
}
|
||||||
|
|
||||||
var path = Path.Combine(".build", Path.ChangeExtension(file, "ll"));
|
var path = Path.Combine(".build", Path.ChangeExtension(file, "ll"));
|
||||||
File.WriteAllText(path, generator.Emit(compilationUnit));
|
File.WriteAllText(path, generator.Emit(compilationUnit, moduleRepository));
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using NubLang.Ast;
|
using NubLang.Ast;
|
||||||
|
using NubLang.Syntax;
|
||||||
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
|
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
|
||||||
using Range = OmniSharp.Extensions.LanguageServer.Protocol.Models.Range;
|
using Range = OmniSharp.Extensions.LanguageServer.Protocol.Models.Range;
|
||||||
|
|
||||||
@@ -20,6 +21,47 @@ public static class AstExtensions
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Location ToLocation(this Token token)
|
||||||
|
{
|
||||||
|
return new Location
|
||||||
|
{
|
||||||
|
Uri = token.Span.FilePath,
|
||||||
|
Range = new Range(token.Span.Start.Line - 1, token.Span.Start.Column - 1, token.Span.End.Line - 1, token.Span.End.Column - 1)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool ContainsPosition(this Token token, int line, int character)
|
||||||
|
{
|
||||||
|
var start = token.Span.Start;
|
||||||
|
var end = token.Span.End;
|
||||||
|
|
||||||
|
var startLine = start.Line - 1;
|
||||||
|
var startChar = start.Column - 1;
|
||||||
|
var endLine = end.Line - 1;
|
||||||
|
var endChar = end.Column - 1;
|
||||||
|
|
||||||
|
if (line < startLine || line > endLine) return false;
|
||||||
|
|
||||||
|
if (line > startLine && line < endLine) return true;
|
||||||
|
|
||||||
|
if (startLine == endLine)
|
||||||
|
{
|
||||||
|
return character >= startChar && character <= endChar;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line == startLine)
|
||||||
|
{
|
||||||
|
return character >= startChar;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line == endLine)
|
||||||
|
{
|
||||||
|
return character <= endChar;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public static bool ContainsPosition(this Node node, int line, int character)
|
public static bool ContainsPosition(this Node node, int line, int character)
|
||||||
{
|
{
|
||||||
if (node.Tokens.Count == 0)
|
if (node.Tokens.Count == 0)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using NubLang.Ast;
|
using NubLang.Ast;
|
||||||
|
using NubLang.Modules;
|
||||||
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,13 +30,6 @@ internal class CompletionHandler(WorkspaceManager workspaceManager) : Completion
|
|||||||
Label = "module",
|
Label = "module",
|
||||||
InsertTextFormat = InsertTextFormat.Snippet,
|
InsertTextFormat = InsertTextFormat.Snippet,
|
||||||
InsertText = "module \"$0\"",
|
InsertText = "module \"$0\"",
|
||||||
},
|
|
||||||
new()
|
|
||||||
{
|
|
||||||
Kind = CompletionItemKind.Keyword,
|
|
||||||
Label = "import",
|
|
||||||
InsertTextFormat = InsertTextFormat.Snippet,
|
|
||||||
InsertText = "import \"$0\"",
|
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -112,65 +106,76 @@ internal class CompletionHandler(WorkspaceManager workspaceManager) : Completion
|
|||||||
private CompletionList HandleSync(CompletionParams request, CancellationToken cancellationToken)
|
private CompletionList HandleSync(CompletionParams request, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var completions = new List<CompletionItem>();
|
var completions = new List<CompletionItem>();
|
||||||
var position = request.Position;
|
|
||||||
|
|
||||||
var uri = request.TextDocument.Uri;
|
var compilationUnit = workspaceManager.GetTopLevelNodes(request.TextDocument.Uri.GetFileSystemPath());
|
||||||
var compilationUnit = workspaceManager.GetCompilationUnit(uri);
|
|
||||||
if (compilationUnit != null)
|
var repository = workspaceManager.GetModuleRepository();
|
||||||
|
|
||||||
|
var function = compilationUnit
|
||||||
|
.OfType<FuncNode>()
|
||||||
|
.FirstOrDefault(x => x.Body != null && x.Body.ContainsPosition(request.Position.Line, request.Position.Character));
|
||||||
|
|
||||||
|
if (function != null)
|
||||||
{
|
{
|
||||||
var function = compilationUnit.OfType<FuncNode>().FirstOrDefault(x => x.Body != null && x.Body.ContainsPosition(position.Line, position.Character));
|
completions.AddRange(_statementSnippets);
|
||||||
if (function != null)
|
|
||||||
|
foreach (var module in repository.GetAll())
|
||||||
{
|
{
|
||||||
completions.AddRange(_statementSnippets);
|
foreach (var prototype in module.FunctionPrototypes)
|
||||||
|
|
||||||
// foreach (var (module, prototypes) in compilationUnit.ImportedFunctions)
|
|
||||||
// {
|
|
||||||
// foreach (var prototype in prototypes)
|
|
||||||
// {
|
|
||||||
// var parameterStrings = new List<string>();
|
|
||||||
// foreach (var (index, parameter) in prototype.Parameters.Index())
|
|
||||||
// {
|
|
||||||
// parameterStrings.AddRange($"${{{index + 1}:{parameter.NameToken.Value}}}");
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// completions.Add(new CompletionItem
|
|
||||||
// {
|
|
||||||
// Kind = CompletionItemKind.Function,
|
|
||||||
// Label = $"{module.Value}::{prototype.NameToken.Value}",
|
|
||||||
// InsertTextFormat = InsertTextFormat.Snippet,
|
|
||||||
// InsertText = $"{module.Value}::{prototype.NameToken.Value}({string.Join(", ", parameterStrings)})",
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
foreach (var parameter in function.Prototype.Parameters)
|
|
||||||
{
|
{
|
||||||
|
var parameterStrings = new List<string>();
|
||||||
|
foreach (var (index, parameter) in prototype.Parameters.Index())
|
||||||
|
{
|
||||||
|
parameterStrings.AddRange($"${{{index + 1}:{parameter.NameToken.Value}}}");
|
||||||
|
}
|
||||||
|
|
||||||
|
var isCurrentModule = false;
|
||||||
|
var moduleDecl = compilationUnit.OfType<ModuleNode>().FirstOrDefault();
|
||||||
|
if (moduleDecl != null)
|
||||||
|
{
|
||||||
|
if (moduleDecl.NameToken.Value == module.Name)
|
||||||
|
{
|
||||||
|
isCurrentModule = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
completions.Add(new CompletionItem
|
completions.Add(new CompletionItem
|
||||||
{
|
{
|
||||||
Kind = CompletionItemKind.Variable,
|
Kind = CompletionItemKind.Function,
|
||||||
Label = parameter.NameToken.Value,
|
Label = isCurrentModule ? prototype.NameToken.Value : $"{module.Name}::{prototype.NameToken.Value}",
|
||||||
InsertText = parameter.NameToken.Value,
|
InsertTextFormat = InsertTextFormat.Snippet,
|
||||||
});
|
InsertText = $"{(isCurrentModule ? "" : $"{module.Name}::")}{prototype.NameToken.Value}({string.Join(", ", parameterStrings)})",
|
||||||
}
|
|
||||||
|
|
||||||
var variables = function.Body!
|
|
||||||
.Descendants()
|
|
||||||
.OfType<VariableDeclarationNode>();
|
|
||||||
|
|
||||||
foreach (var variable in variables)
|
|
||||||
{
|
|
||||||
completions.Add(new CompletionItem
|
|
||||||
{
|
|
||||||
Kind = CompletionItemKind.Variable,
|
|
||||||
Label = variable.NameToken.Value,
|
|
||||||
InsertText = variable.NameToken.Value,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
foreach (var parameter in function.Prototype.Parameters)
|
||||||
{
|
{
|
||||||
completions.AddRange(_definitionSnippets);
|
completions.Add(new CompletionItem
|
||||||
|
{
|
||||||
|
Kind = CompletionItemKind.Variable,
|
||||||
|
Label = parameter.NameToken.Value,
|
||||||
|
InsertText = parameter.NameToken.Value,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var variables = function.Body!
|
||||||
|
.Descendants()
|
||||||
|
.OfType<VariableDeclarationNode>();
|
||||||
|
|
||||||
|
foreach (var variable in variables)
|
||||||
|
{
|
||||||
|
completions.Add(new CompletionItem
|
||||||
|
{
|
||||||
|
Kind = CompletionItemKind.Variable,
|
||||||
|
Label = variable.NameToken.Value,
|
||||||
|
InsertText = variable.NameToken.Value,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
completions.AddRange(_definitionSnippets);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new CompletionList(completions, false);
|
return new CompletionList(completions, false);
|
||||||
|
|||||||
@@ -20,37 +20,58 @@ internal class DefinitionHandler(WorkspaceManager workspaceManager) : Definition
|
|||||||
private LocationOrLocationLinks? HandleSync(DefinitionParams request, CancellationToken cancellationToken)
|
private LocationOrLocationLinks? HandleSync(DefinitionParams request, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var uri = request.TextDocument.Uri;
|
var uri = request.TextDocument.Uri;
|
||||||
var compilationUnit = workspaceManager.GetCompilationUnit(uri);
|
var topLevelNodes = workspaceManager.GetTopLevelNodes(uri.GetFileSystemPath());
|
||||||
if (compilationUnit == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var line = request.Position.Line;
|
var line = request.Position.Line;
|
||||||
var character = request.Position.Character;
|
var character = request.Position.Character;
|
||||||
|
|
||||||
var node = compilationUnit.DeepestNodeAtPosition(line, character);
|
var node = topLevelNodes.DeepestNodeAtPosition(line, character);
|
||||||
|
|
||||||
switch (node)
|
switch (node)
|
||||||
{
|
{
|
||||||
case VariableIdentifierNode variableIdentifierNode:
|
case VariableIdentifierNode variableIdentifierNode:
|
||||||
{
|
{
|
||||||
var function = compilationUnit.FunctionAtPosition(line, character);
|
var funcNode = topLevelNodes.FunctionAtPosition(line, character);
|
||||||
|
|
||||||
var parameter = function?.Prototype.Parameters.FirstOrDefault(x => x.NameToken.Value == variableIdentifierNode.NameToken.Value);
|
var parameter = funcNode?.Prototype.Parameters.FirstOrDefault(x => x.NameToken.Value == variableIdentifierNode.NameToken.Value);
|
||||||
if (parameter != null)
|
if (parameter != null)
|
||||||
{
|
{
|
||||||
return new LocationOrLocationLinks(parameter.ToLocation());
|
return new LocationOrLocationLinks(parameter.NameToken.ToLocation());
|
||||||
}
|
}
|
||||||
|
|
||||||
var variable = function?.Body?
|
var variable = funcNode?.Body?
|
||||||
.Descendants()
|
.Descendants()
|
||||||
.OfType<VariableDeclarationNode>()
|
.OfType<VariableDeclarationNode>()
|
||||||
.FirstOrDefault(x => x.NameToken.Value == variableIdentifierNode.NameToken.Value);
|
.FirstOrDefault(x => x.NameToken.Value == variableIdentifierNode.NameToken.Value);
|
||||||
|
|
||||||
if (variable != null)
|
if (variable != null)
|
||||||
{
|
{
|
||||||
return new LocationOrLocationLinks(variable.ToLocation());
|
return new LocationOrLocationLinks(variable.NameToken.ToLocation());
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
case LocalFuncIdentifierNode localFuncIdentifierNode:
|
||||||
|
{
|
||||||
|
var funcNode = topLevelNodes.OfType<FuncNode>().FirstOrDefault(x => x.NameToken.Value == localFuncIdentifierNode.NameToken.Value);
|
||||||
|
if (funcNode != null)
|
||||||
|
{
|
||||||
|
return new LocationOrLocationLinks(funcNode.NameToken.ToLocation());
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
case ModuleFuncIdentifierNode localFuncIdentifierNode:
|
||||||
|
{
|
||||||
|
var repository = workspaceManager.GetModuleRepository();
|
||||||
|
if (!repository.TryGet(localFuncIdentifierNode.ModuleToken, out var module))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (module.TryResolveFunc(localFuncIdentifierNode.NameToken, out var func, out _))
|
||||||
|
{
|
||||||
|
return new LocationOrLocationLinks(func.NameToken.ToLocation());
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -25,24 +25,15 @@ internal class HoverHandler(WorkspaceManager workspaceManager) : HoverHandlerBas
|
|||||||
|
|
||||||
private Hover? HandleSync(HoverParams request, CancellationToken cancellationToken)
|
private Hover? HandleSync(HoverParams request, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var compilationUnit = workspaceManager.GetCompilationUnit(request.TextDocument.Uri);
|
var topLevelNodes = workspaceManager.GetTopLevelNodes(request.TextDocument.Uri.GetFileSystemPath());
|
||||||
if (compilationUnit == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var moduleDecl = compilationUnit.OfType<ModuleNode>().FirstOrDefault();
|
var moduleDecl = topLevelNodes.OfType<ModuleNode>().FirstOrDefault();
|
||||||
if (moduleDecl == null)
|
if (moduleDecl == null)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var moduleRepository = workspaceManager.GetModuleRepository();
|
var moduleRepository = workspaceManager.GetModuleRepository();
|
||||||
if (moduleRepository == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!moduleRepository.TryGet(moduleDecl.NameToken, out var module))
|
if (!moduleRepository.TryGet(moduleDecl.NameToken, out var module))
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
@@ -51,14 +42,14 @@ internal class HoverHandler(WorkspaceManager workspaceManager) : HoverHandlerBas
|
|||||||
var line = request.Position.Line;
|
var line = request.Position.Line;
|
||||||
var character = request.Position.Character;
|
var character = request.Position.Character;
|
||||||
|
|
||||||
var hoveredNode = compilationUnit.DeepestNodeAtPosition(line, character);
|
var hoveredNode = topLevelNodes.DeepestNodeAtPosition(line, character);
|
||||||
|
|
||||||
if (hoveredNode == null)
|
if (hoveredNode == null)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var message = CreateMessage(hoveredNode, moduleRepository, module);
|
var message = CreateMessage(hoveredNode, moduleRepository, module, line, character);
|
||||||
if (message == null)
|
if (message == null)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
@@ -74,7 +65,7 @@ internal class HoverHandler(WorkspaceManager workspaceManager) : HoverHandlerBas
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string? CreateMessage(Node hoveredNode, ModuleRepository repository, ModuleRepository.Module currentModule)
|
private static string? CreateMessage(Node hoveredNode, ModuleRepository repository, ModuleRepository.Module currentModule, int line, int character)
|
||||||
{
|
{
|
||||||
return hoveredNode switch
|
return hoveredNode switch
|
||||||
{
|
{
|
||||||
@@ -99,6 +90,7 @@ internal class HoverHandler(WorkspaceManager workspaceManager) : HoverHandlerBas
|
|||||||
U16LiteralNode u16LiteralNode => CreateLiteralMessage(u16LiteralNode.Type, u16LiteralNode.Value.ToString()),
|
U16LiteralNode u16LiteralNode => CreateLiteralMessage(u16LiteralNode.Type, u16LiteralNode.Value.ToString()),
|
||||||
U32LiteralNode u32LiteralNode => CreateLiteralMessage(u32LiteralNode.Type, u32LiteralNode.Value.ToString()),
|
U32LiteralNode u32LiteralNode => CreateLiteralMessage(u32LiteralNode.Type, u32LiteralNode.Value.ToString()),
|
||||||
U64LiteralNode u64LiteralNode => CreateLiteralMessage(u64LiteralNode.Type, u64LiteralNode.Value.ToString()),
|
U64LiteralNode u64LiteralNode => CreateLiteralMessage(u64LiteralNode.Type, u64LiteralNode.Value.ToString()),
|
||||||
|
StructInitializerNode structInitializerNode => CreateStructInitializerMessage(structInitializerNode, line, character),
|
||||||
// Expressions can have a generic fallback showing the resulting type
|
// Expressions can have a generic fallback showing the resulting type
|
||||||
ExpressionNode expressionNode => $"""
|
ExpressionNode expressionNode => $"""
|
||||||
**Expression** `{expressionNode.GetType().Name}`
|
**Expression** `{expressionNode.GetType().Name}`
|
||||||
@@ -111,6 +103,41 @@ internal class HoverHandler(WorkspaceManager workspaceManager) : HoverHandlerBas
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string CreateStructInitializerMessage(StructInitializerNode structInitializerNode, int line, int character)
|
||||||
|
{
|
||||||
|
var hoveredInitializerName = structInitializerNode
|
||||||
|
.Initializers
|
||||||
|
.Select(x => x.Key)
|
||||||
|
.FirstOrDefault(x => x.ContainsPosition(line, character));
|
||||||
|
|
||||||
|
var structType = (NubStructType)structInitializerNode.Type;
|
||||||
|
|
||||||
|
if (hoveredInitializerName != null)
|
||||||
|
{
|
||||||
|
var field = structType.Fields.FirstOrDefault(x => x.Name == hoveredInitializerName.Value);
|
||||||
|
if (field != null)
|
||||||
|
{
|
||||||
|
return $"""
|
||||||
|
**Field** in `{structType}`
|
||||||
|
```nub
|
||||||
|
{hoveredInitializerName.Value}: {field.Type}
|
||||||
|
```
|
||||||
|
""";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return $"""
|
||||||
|
**Field** in `{structType}`
|
||||||
|
```nub
|
||||||
|
// Field not found
|
||||||
|
```
|
||||||
|
""";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $"**Struct initializer** `{structType}`";
|
||||||
|
}
|
||||||
|
|
||||||
private static string CreateLiteralMessage(NubType type, string value)
|
private static string CreateLiteralMessage(NubType type, string value)
|
||||||
{
|
{
|
||||||
return $"""
|
return $"""
|
||||||
|
|||||||
@@ -15,25 +15,25 @@ internal class TextDocumentSyncHandler(WorkspaceManager workspaceManager) : Text
|
|||||||
|
|
||||||
public override Task<Unit> Handle(DidOpenTextDocumentParams request, CancellationToken cancellationToken)
|
public override Task<Unit> Handle(DidOpenTextDocumentParams request, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
workspaceManager.UpdateFile(request.TextDocument.Uri.GetFileSystemPath());
|
workspaceManager.Update();
|
||||||
return Unit.Task;
|
return Unit.Task;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Task<Unit> Handle(DidChangeTextDocumentParams request, CancellationToken cancellationToken)
|
public override Task<Unit> Handle(DidChangeTextDocumentParams request, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
workspaceManager.UpdateFile(request.TextDocument.Uri.GetFileSystemPath());
|
workspaceManager.Update();
|
||||||
return Unit.Task;
|
return Unit.Task;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Task<Unit> Handle(DidSaveTextDocumentParams request, CancellationToken cancellationToken)
|
public override Task<Unit> Handle(DidSaveTextDocumentParams request, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
workspaceManager.UpdateFile(request.TextDocument.Uri.GetFileSystemPath());
|
workspaceManager.Update();
|
||||||
return Unit.Task;
|
return Unit.Task;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Task<Unit> Handle(DidCloseTextDocumentParams request, CancellationToken cancellationToken)
|
public override Task<Unit> Handle(DidCloseTextDocumentParams request, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
workspaceManager.UpdateFile(request.TextDocument.Uri.GetFileSystemPath());
|
workspaceManager.Update();
|
||||||
return Unit.Task;
|
return Unit.Task;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,100 +2,67 @@ using NubLang.Ast;
|
|||||||
using NubLang.Diagnostics;
|
using NubLang.Diagnostics;
|
||||||
using NubLang.Modules;
|
using NubLang.Modules;
|
||||||
using NubLang.Syntax;
|
using NubLang.Syntax;
|
||||||
using OmniSharp.Extensions.LanguageServer.Protocol;
|
|
||||||
|
|
||||||
namespace NubLang.LSP;
|
namespace NubLang.LSP;
|
||||||
|
|
||||||
public class WorkspaceManager(DiagnosticsPublisher diagnosticsPublisher)
|
public class WorkspaceManager(DiagnosticsPublisher diagnosticsPublisher)
|
||||||
{
|
{
|
||||||
private readonly Dictionary<string, SyntaxTree> _syntaxTrees = new();
|
private record Unit(SyntaxTree SyntaxTree, DateTimeOffset FileTimestamp, List<Diagnostic> Diagnostics);
|
||||||
private readonly Dictionary<string, List<TopLevelNode>> _compilationUnits = new();
|
|
||||||
private ModuleRepository? _repository;
|
private readonly Tokenizer _tokenizer = new();
|
||||||
|
private readonly Parser _parser = new();
|
||||||
|
private readonly TypeChecker _typeChecker = new();
|
||||||
|
private string? _rootPath;
|
||||||
|
private readonly Dictionary<string, Unit> _units = [];
|
||||||
|
private readonly Dictionary<string, List<TopLevelNode>> _possiblyOutdatedTopLevelNodes = [];
|
||||||
|
private ModuleRepository _repository = new([]);
|
||||||
|
|
||||||
public void Init(string rootPath)
|
public void Init(string rootPath)
|
||||||
{
|
{
|
||||||
var files = Directory.GetFiles(rootPath, "*.nub", SearchOption.AllDirectories);
|
_rootPath = rootPath;
|
||||||
foreach (var path in files)
|
Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update()
|
||||||
|
{
|
||||||
|
if (_rootPath == null) return;
|
||||||
|
var files = Directory.GetFiles(_rootPath, "*.nub", SearchOption.AllDirectories);
|
||||||
|
foreach (var file in files)
|
||||||
{
|
{
|
||||||
var text = File.ReadAllText(path);
|
var lastUpdated = File.GetLastWriteTimeUtc(file);
|
||||||
var tokenizer = new Tokenizer();
|
var unit = _units.GetValueOrDefault(file);
|
||||||
|
if (unit == null || lastUpdated > unit.FileTimestamp)
|
||||||
tokenizer.Tokenize(path, text);
|
|
||||||
diagnosticsPublisher.Publish(path, tokenizer.Diagnostics);
|
|
||||||
|
|
||||||
var parser = new Parser();
|
|
||||||
var parseResult = parser.Parse(tokenizer.Tokens);
|
|
||||||
diagnosticsPublisher.Publish(path, parser.Diagnostics);
|
|
||||||
|
|
||||||
_syntaxTrees[path] = parseResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
ModuleRepository repository;
|
|
||||||
|
|
||||||
foreach (var (fsPath, syntaxTree) in _syntaxTrees)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
repository = ModuleRepository.Create(_syntaxTrees.Select(x => x.Value).ToList());
|
_units[file] = Update(file, lastUpdated);
|
||||||
}
|
|
||||||
catch (CompileException e)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var typeChecker = new TypeChecker();
|
_repository = ModuleRepository.Create(_units.Select(x => x.Value.SyntaxTree).ToList());
|
||||||
var result = typeChecker.Check(syntaxTree, repository);
|
|
||||||
diagnosticsPublisher.Publish(fsPath, typeChecker.Diagnostics);
|
foreach (var (file, unit) in _units)
|
||||||
_compilationUnits[fsPath] = result;
|
{
|
||||||
|
var topLevelNodes = _typeChecker.Check(unit.SyntaxTree, _repository);
|
||||||
|
_possiblyOutdatedTopLevelNodes[file] = topLevelNodes;
|
||||||
|
diagnosticsPublisher.Publish(file, [..unit.Diagnostics, .._typeChecker.Diagnostics]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateFile(DocumentUri path)
|
private Unit Update(string file, DateTimeOffset lastUpdated)
|
||||||
{
|
{
|
||||||
var fsPath = path.GetFileSystemPath();
|
var text = File.ReadAllText(file);
|
||||||
|
var tokens = _tokenizer.Tokenize(file, text);
|
||||||
|
var syntaxTree = _parser.Parse(tokens);
|
||||||
|
|
||||||
var text = File.ReadAllText(fsPath);
|
return new Unit(syntaxTree, lastUpdated, [.._tokenizer.Diagnostics, .._parser.Diagnostics]);
|
||||||
var tokenizer = new Tokenizer();
|
|
||||||
tokenizer.Tokenize(fsPath, text);
|
|
||||||
diagnosticsPublisher.Publish(path, tokenizer.Diagnostics);
|
|
||||||
|
|
||||||
var parser = new Parser();
|
|
||||||
var syntaxTree = parser.Parse(tokenizer.Tokens);
|
|
||||||
diagnosticsPublisher.Publish(path, parser.Diagnostics);
|
|
||||||
_syntaxTrees[fsPath] = syntaxTree;
|
|
||||||
|
|
||||||
ModuleRepository repository;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
repository = ModuleRepository.Create(_syntaxTrees.Select(x => x.Value).ToList());
|
|
||||||
}
|
|
||||||
catch (CompileException e)
|
|
||||||
{
|
|
||||||
diagnosticsPublisher.Publish(path, [e.Diagnostic]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var typeChecker = new TypeChecker();
|
|
||||||
var result = typeChecker.Check(syntaxTree, repository);
|
|
||||||
diagnosticsPublisher.Publish(fsPath, typeChecker.Diagnostics);
|
|
||||||
_compilationUnits[fsPath] = result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<TopLevelNode>? GetCompilationUnit(DocumentUri path)
|
public List<TopLevelNode> GetTopLevelNodes(string path)
|
||||||
{
|
{
|
||||||
return _compilationUnits.GetValueOrDefault(path.GetFileSystemPath());
|
return _possiblyOutdatedTopLevelNodes.GetValueOrDefault(path, []);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ModuleRepository? GetModuleRepository()
|
public ModuleRepository GetModuleRepository()
|
||||||
{
|
{
|
||||||
try
|
return _repository;
|
||||||
{
|
|
||||||
return ModuleRepository.Create(_syntaxTrees.Select(x => x.Value).ToList());
|
|
||||||
}
|
|
||||||
catch (CompileException e)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -106,7 +106,7 @@ public class Diagnostic
|
|||||||
var text = File.ReadAllText(Span.Value.FilePath);
|
var text = File.ReadAllText(Span.Value.FilePath);
|
||||||
|
|
||||||
var tokenizer = new Tokenizer();
|
var tokenizer = new Tokenizer();
|
||||||
tokenizer.Tokenize(Span.Value.FilePath, text);
|
var tokens = tokenizer.Tokenize(Span.Value.FilePath, text);
|
||||||
|
|
||||||
var lines = text.Split('\n');
|
var lines = text.Split('\n');
|
||||||
|
|
||||||
@@ -144,7 +144,7 @@ public class Diagnostic
|
|||||||
sb.Append("│ ");
|
sb.Append("│ ");
|
||||||
sb.Append(i.ToString().PadRight(numberPadding));
|
sb.Append(i.ToString().PadRight(numberPadding));
|
||||||
sb.Append(" │ ");
|
sb.Append(" │ ");
|
||||||
sb.Append(ApplySyntaxHighlighting(line.PadRight(codePadding), i, tokenizer.Tokens));
|
sb.Append(ApplySyntaxHighlighting(line.PadRight(codePadding), i, tokens));
|
||||||
// sb.Append(line.PadRight(codePadding));
|
// sb.Append(line.PadRight(codePadding));
|
||||||
sb.Append(" │");
|
sb.Append(" │");
|
||||||
sb.AppendLine();
|
sb.AppendLine();
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using NubLang.Ast;
|
using NubLang.Ast;
|
||||||
|
using NubLang.Modules;
|
||||||
using NubLang.Types;
|
using NubLang.Types;
|
||||||
|
|
||||||
namespace NubLang.Generation;
|
namespace NubLang.Generation;
|
||||||
@@ -12,7 +13,7 @@ public class LlvmGenerator
|
|||||||
private List<(string Name, int Size, string Text)> _stringLiterals = [];
|
private List<(string Name, int Size, string Text)> _stringLiterals = [];
|
||||||
private Stack<(string breakLabel, string continueLabel)> _loopStack = [];
|
private Stack<(string breakLabel, string continueLabel)> _loopStack = [];
|
||||||
|
|
||||||
public string Emit(List<TopLevelNode> topLevelNodes)
|
public string Emit(List<TopLevelNode> topLevelNodes, ModuleRepository repository)
|
||||||
{
|
{
|
||||||
_stringLiterals = [];
|
_stringLiterals = [];
|
||||||
_loopStack = [];
|
_loopStack = [];
|
||||||
@@ -26,6 +27,30 @@ public class LlvmGenerator
|
|||||||
writer.WriteLine("declare void @llvm.memcpy.p0.p0.i64(ptr, ptr, i64, i1)");
|
writer.WriteLine("declare void @llvm.memcpy.p0.p0.i64(ptr, ptr, i64, i1)");
|
||||||
writer.WriteLine();
|
writer.WriteLine();
|
||||||
|
|
||||||
|
var declaredExternFunctions = new HashSet<string>();
|
||||||
|
|
||||||
|
foreach (var module in repository.GetAll())
|
||||||
|
{
|
||||||
|
foreach (var prototype in module.FunctionPrototypes)
|
||||||
|
{
|
||||||
|
// note(nub31): If we are in the current module and the function has a body, we skip it to prevent duplicate definition
|
||||||
|
if (module.Name == _module && topLevelNodes.OfType<FuncNode>().First(x => x.NameToken.Value == prototype.NameToken.Value).Body != null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prototype.ExternSymbolToken != null && !declaredExternFunctions.Add(prototype.ExternSymbolToken.Value))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var parameters = prototype.Parameters.Select(x => $"{MapType(x.Type)} %{x.NameToken.Value}");
|
||||||
|
var funcName = FuncName(module.Name, prototype.NameToken.Value, prototype.ExternSymbolToken?.Value);
|
||||||
|
writer.WriteLine($"declare {MapType(prototype.ReturnType)} @{funcName}({string.Join(", ", parameters)})");
|
||||||
|
writer.WriteLine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var structNode in topLevelNodes.OfType<StructNode>())
|
foreach (var structNode in topLevelNodes.OfType<StructNode>())
|
||||||
{
|
{
|
||||||
var types = structNode.Fields.Select(x => MapType(x.Type));
|
var types = structNode.Fields.Select(x => MapType(x.Type));
|
||||||
@@ -57,15 +82,6 @@ public class LlvmGenerator
|
|||||||
writer.WriteLine();
|
writer.WriteLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var funcNode in topLevelNodes.OfType<FuncNode>())
|
|
||||||
{
|
|
||||||
if (funcNode.Body != null) continue;
|
|
||||||
var parameters = funcNode.Prototype.Parameters.Select(x => $"{MapType(x.Type)} %{x.NameToken.Value}");
|
|
||||||
|
|
||||||
writer.WriteLine($"declare {MapType(funcNode.Prototype.ReturnType)} @{FuncName(funcNode.Prototype)}({string.Join(", ", parameters)})");
|
|
||||||
writer.WriteLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var funcNode in topLevelNodes.OfType<FuncNode>())
|
foreach (var funcNode in topLevelNodes.OfType<FuncNode>())
|
||||||
{
|
{
|
||||||
if (funcNode.Body == null) continue;
|
if (funcNode.Body == null) continue;
|
||||||
@@ -335,7 +351,8 @@ public class LlvmGenerator
|
|||||||
Float32LiteralNode float32LiteralNode => EmitFloat32Literal(writer, float32LiteralNode),
|
Float32LiteralNode float32LiteralNode => EmitFloat32Literal(writer, float32LiteralNode),
|
||||||
Float64LiteralNode float64LiteralNode => EmitFloat64Literal(writer, float64LiteralNode),
|
Float64LiteralNode float64LiteralNode => EmitFloat64Literal(writer, float64LiteralNode),
|
||||||
FuncCallNode funcCallNode => EmitFuncCall(writer, funcCallNode),
|
FuncCallNode funcCallNode => EmitFuncCall(writer, funcCallNode),
|
||||||
ModuleFuncIdentifierNode funcIdentifierNode => EmitFuncIdentifier(writer, funcIdentifierNode),
|
ModuleFuncIdentifierNode moduleFuncIdentifierNode => EmitModuleFuncIdentifier(writer, moduleFuncIdentifierNode),
|
||||||
|
LocalFuncIdentifierNode localFuncIdentifierNode => EmitLocalFuncIdentifier(writer, localFuncIdentifierNode),
|
||||||
I16LiteralNode i16LiteralNode => EmitI16Literal(writer, i16LiteralNode),
|
I16LiteralNode i16LiteralNode => EmitI16Literal(writer, i16LiteralNode),
|
||||||
I32LiteralNode i32LiteralNode => EmitI32Literal(writer, i32LiteralNode),
|
I32LiteralNode i32LiteralNode => EmitI32Literal(writer, i32LiteralNode),
|
||||||
I64LiteralNode i64LiteralNode => EmitI64Literal(writer, i64LiteralNode),
|
I64LiteralNode i64LiteralNode => EmitI64Literal(writer, i64LiteralNode),
|
||||||
@@ -769,12 +786,18 @@ public class LlvmGenerator
|
|||||||
return new Tmp(result, funcCallNode.Type, false);
|
return new Tmp(result, funcCallNode.Type, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Tmp EmitFuncIdentifier(IndentedTextWriter writer, ModuleFuncIdentifierNode moduleFuncIdentifierNode)
|
private Tmp EmitModuleFuncIdentifier(IndentedTextWriter writer, ModuleFuncIdentifierNode moduleFuncIdentifierNode)
|
||||||
{
|
{
|
||||||
var name = FuncName(moduleFuncIdentifierNode.ModuleToken.Value, moduleFuncIdentifierNode.NameToken.Value, moduleFuncIdentifierNode.ExternSymbolToken?.Value);
|
var name = FuncName(moduleFuncIdentifierNode.ModuleToken.Value, moduleFuncIdentifierNode.NameToken.Value, moduleFuncIdentifierNode.ExternSymbolToken?.Value);
|
||||||
return new Tmp($"@{name}", moduleFuncIdentifierNode.Type, false);
|
return new Tmp($"@{name}", moduleFuncIdentifierNode.Type, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Tmp EmitLocalFuncIdentifier(IndentedTextWriter writer, LocalFuncIdentifierNode localFuncIdentifierNode)
|
||||||
|
{
|
||||||
|
var name = FuncName(_module, localFuncIdentifierNode.NameToken.Value, localFuncIdentifierNode.ExternSymbolToken?.Value);
|
||||||
|
return new Tmp($"@{name}", localFuncIdentifierNode.Type, false);
|
||||||
|
}
|
||||||
|
|
||||||
private Tmp EmitI16Literal(IndentedTextWriter writer, I16LiteralNode i16LiteralNode)
|
private Tmp EmitI16Literal(IndentedTextWriter writer, I16LiteralNode i16LiteralNode)
|
||||||
{
|
{
|
||||||
return new Tmp(i16LiteralNode.Value.ToString(), i16LiteralNode.Type, false);
|
return new Tmp(i16LiteralNode.Value.ToString(), i16LiteralNode.Type, false);
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ public sealed class ModuleRepository
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ModuleRepository(Dictionary<string, Module> modules)
|
public ModuleRepository(Dictionary<string, Module> modules)
|
||||||
{
|
{
|
||||||
_modules = modules;
|
_modules = modules;
|
||||||
}
|
}
|
||||||
@@ -167,6 +167,17 @@ public sealed class ModuleRepository
|
|||||||
return module != null;
|
return module != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool TryGet(string name, [NotNullWhen(true)] out Module? module)
|
||||||
|
{
|
||||||
|
module = _modules.GetValueOrDefault(name);
|
||||||
|
return module != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Module> GetAll()
|
||||||
|
{
|
||||||
|
return _modules.Values.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
public sealed class Module
|
public sealed class Module
|
||||||
{
|
{
|
||||||
public required string Name { get; init; }
|
public required string Name { get; init; }
|
||||||
@@ -174,6 +185,21 @@ public sealed class ModuleRepository
|
|||||||
public required List<NubStructType> StructTypes { get; init; } = [];
|
public required List<NubStructType> StructTypes { get; init; } = [];
|
||||||
public required Dictionary<string, NubIntType> EnumTypes { get; init; } = [];
|
public required Dictionary<string, NubIntType> EnumTypes { get; init; } = [];
|
||||||
|
|
||||||
|
public bool TryResolveFunc(string name, [NotNullWhen(true)] out FuncPrototypeNode? value, [NotNullWhen(false)] out Diagnostic? diagnostic)
|
||||||
|
{
|
||||||
|
value = FunctionPrototypes.FirstOrDefault(x => x.NameToken.Value == name);
|
||||||
|
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
value = null;
|
||||||
|
diagnostic = Diagnostic.Error($"Func {name} not found in module {Name}").Build();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
diagnostic = null;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public bool TryResolveFunc(IdentifierToken name, [NotNullWhen(true)] out FuncPrototypeNode? value, [NotNullWhen(false)] out Diagnostic? diagnostic)
|
public bool TryResolveFunc(IdentifierToken name, [NotNullWhen(true)] out FuncPrototypeNode? value, [NotNullWhen(false)] out Diagnostic? diagnostic)
|
||||||
{
|
{
|
||||||
value = FunctionPrototypes.FirstOrDefault(x => x.NameToken.Value == name.Value);
|
value = FunctionPrototypes.FirstOrDefault(x => x.NameToken.Value == name.Value);
|
||||||
@@ -199,6 +225,21 @@ public sealed class ModuleRepository
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool TryResolveStruct(string name, [NotNullWhen(true)] out NubStructType? value, [NotNullWhen(false)] out Diagnostic? diagnostic)
|
||||||
|
{
|
||||||
|
value = StructTypes.FirstOrDefault(x => x.Name == name);
|
||||||
|
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
value = null;
|
||||||
|
diagnostic = Diagnostic.Error($"Struct {name} not found in module {Name}").Build();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
diagnostic = null;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public bool TryResolveStruct(IdentifierToken name, [NotNullWhen(true)] out NubStructType? value, [NotNullWhen(false)] out Diagnostic? diagnostic)
|
public bool TryResolveStruct(IdentifierToken name, [NotNullWhen(true)] out NubStructType? value, [NotNullWhen(false)] out Diagnostic? diagnostic)
|
||||||
{
|
{
|
||||||
value = StructTypes.FirstOrDefault(x => x.Name == name.Value);
|
value = StructTypes.FirstOrDefault(x => x.Name == name.Value);
|
||||||
@@ -224,6 +265,21 @@ public sealed class ModuleRepository
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool TryResolveEnum(string name, [NotNullWhen(true)] out NubIntType? value, [NotNullWhen(false)] out Diagnostic? diagnostic)
|
||||||
|
{
|
||||||
|
value = EnumTypes.GetValueOrDefault(name);
|
||||||
|
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
value = null;
|
||||||
|
diagnostic = Diagnostic.Error($"Enum {name} not found in module {Name}").Build();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
diagnostic = null;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public bool TryResolveEnum(IdentifierToken name, [NotNullWhen(true)] out NubIntType? value, [NotNullWhen(false)] out Diagnostic? diagnostic)
|
public bool TryResolveEnum(IdentifierToken name, [NotNullWhen(true)] out NubIntType? value, [NotNullWhen(false)] out Diagnostic? diagnostic)
|
||||||
{
|
{
|
||||||
value = EnumTypes.GetValueOrDefault(name.Value);
|
value = EnumTypes.GetValueOrDefault(name.Value);
|
||||||
|
|||||||
@@ -417,7 +417,7 @@ public sealed class Parser
|
|||||||
case Symbol.Pipe:
|
case Symbol.Pipe:
|
||||||
binaryExpressionOperator = BinaryOperatorSyntax.BitwiseOr;
|
binaryExpressionOperator = BinaryOperatorSyntax.BitwiseOr;
|
||||||
return true;
|
return true;
|
||||||
case Symbol.XOr:
|
case Symbol.Tilde:
|
||||||
binaryExpressionOperator = BinaryOperatorSyntax.BitwiseXor;
|
binaryExpressionOperator = BinaryOperatorSyntax.BitwiseXor;
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
@@ -439,12 +439,12 @@ public sealed class Parser
|
|||||||
IdentifierToken identifier => ParseIdentifier(startIndex, identifier),
|
IdentifierToken identifier => ParseIdentifier(startIndex, identifier),
|
||||||
SymbolToken symbolToken => symbolToken.Symbol switch
|
SymbolToken symbolToken => symbolToken.Symbol switch
|
||||||
{
|
{
|
||||||
Symbol.Ampersand => new AddressOfSyntax(GetTokens(startIndex), ParsePrimaryExpression()),
|
Symbol.Ampersand => ParseAddressOf(startIndex),
|
||||||
Symbol.OpenParen => ParseParenthesizedExpression(),
|
Symbol.OpenParen => ParseParenthesizedExpression(),
|
||||||
Symbol.Minus => new UnaryExpressionSyntax(GetTokens(startIndex), UnaryOperatorSyntax.Negate, ParsePrimaryExpression()),
|
Symbol.Minus => ParseUnaryNegate(startIndex),
|
||||||
Symbol.Bang => new UnaryExpressionSyntax(GetTokens(startIndex), UnaryOperatorSyntax.Invert, ParsePrimaryExpression()),
|
Symbol.Bang => ParseUnaryInvert(startIndex),
|
||||||
Symbol.OpenBracket => ParseArrayInitializer(startIndex),
|
Symbol.OpenBracket => ParseArrayInitializer(startIndex),
|
||||||
Symbol.OpenBrace => new StructInitializerSyntax(GetTokens(startIndex), null, ParseStructInitializerBody()),
|
Symbol.OpenBrace => ParseUnnamedStructInitializer(startIndex),
|
||||||
Symbol.Struct => ParseStructInitializer(startIndex),
|
Symbol.Struct => ParseStructInitializer(startIndex),
|
||||||
Symbol.At => ParseBuiltinFunction(startIndex),
|
Symbol.At => ParseBuiltinFunction(startIndex),
|
||||||
_ => throw new CompileException(Diagnostic
|
_ => throw new CompileException(Diagnostic
|
||||||
@@ -463,6 +463,24 @@ public sealed class Parser
|
|||||||
return ParsePostfixOperators(expr);
|
return ParsePostfixOperators(expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private AddressOfSyntax ParseAddressOf(int startIndex)
|
||||||
|
{
|
||||||
|
var expression = ParsePrimaryExpression();
|
||||||
|
return new AddressOfSyntax(GetTokens(startIndex), expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
private UnaryExpressionSyntax ParseUnaryInvert(int startIndex)
|
||||||
|
{
|
||||||
|
var expression = ParsePrimaryExpression();
|
||||||
|
return new UnaryExpressionSyntax(GetTokens(startIndex), UnaryOperatorSyntax.Invert, expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
private UnaryExpressionSyntax ParseUnaryNegate(int startIndex)
|
||||||
|
{
|
||||||
|
var expression = ParsePrimaryExpression();
|
||||||
|
return new UnaryExpressionSyntax(GetTokens(startIndex), UnaryOperatorSyntax.Negate, expression);
|
||||||
|
}
|
||||||
|
|
||||||
private ExpressionSyntax ParseBuiltinFunction(int startIndex)
|
private ExpressionSyntax ParseBuiltinFunction(int startIndex)
|
||||||
{
|
{
|
||||||
var name = ExpectIdentifier();
|
var name = ExpectIdentifier();
|
||||||
@@ -587,6 +605,12 @@ public sealed class Parser
|
|||||||
return new StructInitializerSyntax(GetTokens(startIndex), type, initializers);
|
return new StructInitializerSyntax(GetTokens(startIndex), type, initializers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private StructInitializerSyntax ParseUnnamedStructInitializer(int startIndex)
|
||||||
|
{
|
||||||
|
var body = ParseStructInitializerBody();
|
||||||
|
return new StructInitializerSyntax(GetTokens(startIndex), null, body);
|
||||||
|
}
|
||||||
|
|
||||||
private Dictionary<IdentifierToken, ExpressionSyntax> ParseStructInitializerBody()
|
private Dictionary<IdentifierToken, ExpressionSyntax> ParseStructInitializerBody()
|
||||||
{
|
{
|
||||||
Dictionary<IdentifierToken, ExpressionSyntax> initializers = [];
|
Dictionary<IdentifierToken, ExpressionSyntax> initializers = [];
|
||||||
|
|||||||
@@ -121,6 +121,7 @@ public enum Symbol
|
|||||||
Star,
|
Star,
|
||||||
ForwardSlash,
|
ForwardSlash,
|
||||||
Caret,
|
Caret,
|
||||||
|
Tilde,
|
||||||
Ampersand,
|
Ampersand,
|
||||||
Semi,
|
Semi,
|
||||||
Percent,
|
Percent,
|
||||||
@@ -129,7 +130,6 @@ public enum Symbol
|
|||||||
Pipe,
|
Pipe,
|
||||||
And,
|
And,
|
||||||
Or,
|
Or,
|
||||||
XOr,
|
|
||||||
At,
|
At,
|
||||||
QuestionMark,
|
QuestionMark,
|
||||||
}
|
}
|
||||||
@@ -189,6 +189,7 @@ public record SymbolToken(SourceSpan Span, Symbol Symbol) : Token(Span)
|
|||||||
Symbol.Pipe => "|",
|
Symbol.Pipe => "|",
|
||||||
Symbol.At => "@",
|
Symbol.At => "@",
|
||||||
Symbol.QuestionMark => "?",
|
Symbol.QuestionMark => "?",
|
||||||
|
Symbol.Tilde => "~",
|
||||||
_ => "none",
|
_ => "none",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,20 +11,20 @@ public sealed class Tokenizer
|
|||||||
private int _column = 1;
|
private int _column = 1;
|
||||||
|
|
||||||
public List<Diagnostic> Diagnostics { get; set; } = new(16);
|
public List<Diagnostic> Diagnostics { get; set; } = new(16);
|
||||||
public List<Token> Tokens { get; set; } = new(256);
|
|
||||||
|
|
||||||
public void Tokenize(string fileName, string content)
|
public List<Token> Tokenize(string fileName, string content)
|
||||||
{
|
{
|
||||||
_fileName = fileName;
|
_fileName = fileName;
|
||||||
_content = content;
|
_content = content;
|
||||||
|
|
||||||
Diagnostics = [];
|
Diagnostics = [];
|
||||||
Tokens = [];
|
|
||||||
|
|
||||||
_index = 0;
|
_index = 0;
|
||||||
_line = 1;
|
_line = 1;
|
||||||
_column = 1;
|
_column = 1;
|
||||||
|
|
||||||
|
var tokens = new List<Token>();
|
||||||
|
|
||||||
while (_index < _content.Length)
|
while (_index < _content.Length)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -54,7 +54,7 @@ public sealed class Tokenizer
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Tokens.Add(ParseToken(current, _line, _column));
|
tokens.Add(ParseToken(current, _line, _column));
|
||||||
}
|
}
|
||||||
catch (CompileException e)
|
catch (CompileException e)
|
||||||
{
|
{
|
||||||
@@ -62,6 +62,8 @@ public sealed class Tokenizer
|
|||||||
Next();
|
Next();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return tokens;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Token ParseToken(char current, int lineStart, int columnStart)
|
private Token ParseToken(char current, int lineStart, int columnStart)
|
||||||
@@ -295,7 +297,6 @@ public sealed class Tokenizer
|
|||||||
"&&" => Symbol.And,
|
"&&" => Symbol.And,
|
||||||
"||" => Symbol.Or,
|
"||" => Symbol.Or,
|
||||||
"::" => Symbol.DoubleColon,
|
"::" => Symbol.DoubleColon,
|
||||||
"x|" => Symbol.XOr,
|
|
||||||
_ => Symbol.None
|
_ => Symbol.None
|
||||||
},
|
},
|
||||||
1 => span[0] switch
|
1 => span[0] switch
|
||||||
@@ -324,6 +325,7 @@ public sealed class Tokenizer
|
|||||||
'|' => Symbol.Pipe,
|
'|' => Symbol.Pipe,
|
||||||
'@' => Symbol.At,
|
'@' => Symbol.At,
|
||||||
'?' => Symbol.QuestionMark,
|
'?' => Symbol.QuestionMark,
|
||||||
|
'~' => Symbol.Tilde,
|
||||||
_ => Symbol.None
|
_ => Symbol.None
|
||||||
},
|
},
|
||||||
_ => Symbol.None
|
_ => Symbol.None
|
||||||
|
|||||||
@@ -2,5 +2,5 @@
|
|||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
nubc main.nub
|
nubc main.nub test.nub
|
||||||
clang .build/main.ll -o .build/out
|
clang .build/main.ll .build/test.ll -o .build/out
|
||||||
@@ -9,5 +9,9 @@ struct Test
|
|||||||
|
|
||||||
extern "main" func main(argc: i64, argv: [?]^i8)
|
extern "main" func main(argc: i64, argv: [?]^i8)
|
||||||
{
|
{
|
||||||
let x: Test = {}
|
let x: Test = {
|
||||||
|
field = 23
|
||||||
|
}
|
||||||
|
|
||||||
|
test::test()
|
||||||
}
|
}
|
||||||
8
examples/playgroud/test.nub
Normal file
8
examples/playgroud/test.nub
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
module test
|
||||||
|
|
||||||
|
extern "puts" func puts(text: ^i8)
|
||||||
|
|
||||||
|
func test()
|
||||||
|
{
|
||||||
|
puts("uwu")
|
||||||
|
}
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
import raylib
|
|
||||||
|
|
||||||
module main
|
module main
|
||||||
|
|
||||||
extern "main" func main(argc: i64, argv: [?]^i8): i64
|
extern "main" func main(argc: i64, argv: [?]^i8): i64
|
||||||
|
|||||||
Reference in New Issue
Block a user