From 236845f0db8613ae0804162a251d34099c5eb9b8 Mon Sep 17 00:00:00 2001 From: Piotr Fusik Date: Mon, 22 Apr 2024 13:22:24 +0200 Subject: [PATCH] [vscode] Go to references. #64 --- Parser.fu | 56 +++--- SymbolReferenceVisitor.fu | 292 ++++++++++++++++++++++++++++++++ editors/vscode/Makefile | 2 +- editors/vscode/README.md | 1 + editors/vscode/src/extension.ts | 79 +++++++-- libfut.cpp | 53 ++---- libfut.cs | 56 +++--- libfut.hpp | 16 +- libfut.js | 61 +++---- 9 files changed, 444 insertions(+), 172 deletions(-) create mode 100644 SymbolReferenceVisitor.fu diff --git a/Parser.fu b/Parser.fu index 17adb657..0f672351 100644 --- a/Parser.fu +++ b/Parser.fu @@ -24,36 +24,20 @@ public class FuParser : FuLexer FuLoop? CurrentLoop = null; FuCondCompletionStatement!? CurrentLoopOrSwitch = null; - string() FindDefinitionFilename; - int FindDefinitionLine = -1; - int FindDefinitionColumn; - FuName? FoundDefinition = null; + string() FindNameFilename; + int FindNameLine = -1; + int FindNameColumn; + FuName? FoundName = null; - public void FindDefinition!(string filename, int line, int column) + public void FindName!(string filename, int line, int column) { - this.FindDefinitionFilename = filename; - this.FindDefinitionLine = line; - this.FindDefinitionColumn = column; - this.FoundDefinition = null; + this.FindNameFilename = filename; + this.FindNameLine = line; + this.FindNameColumn = column; + this.FoundName = null; } - public string? GetFoundDefinitionFilename!() - { - if (this.FoundDefinition == null || this.FoundDefinition.GetSymbol() == null) - return null; - int loc = this.FoundDefinition.GetSymbol().Loc; - if (loc <= 0) - return null; - int line = this.Host.Program.GetLine(loc); - FuSourceFile file = this.Host.Program.GetSourceFile(line); - this.FindDefinitionLine = line - file.Line; - this.FindDefinitionColumn = loc - this.Host.Program.LineLocs[line]; - return file.Filename; - } - - public int GetFoundDefinitionLine() => this.FindDefinitionLine; - - public int GetFoundDefinitionColumn() => this.FindDefinitionColumn; + public FuSymbol? GetFoundDefinition() => this.FoundName == null ? null : this.FoundName.GetSymbol(); bool DocParseLine!(FuDocPara! para) { @@ -200,11 +184,11 @@ public class FuParser : FuLexer return result; } - bool IsFindDefinition() + bool IsFindName() { FuSourceFile file = this.Host.Program.SourceFiles.Last(); - if (this.Host.Program.LineLocs.Count - file.Line - 1 == this.FindDefinitionLine && file.Filename == this.FindDefinitionFilename) { - int loc = this.Host.Program.LineLocs.Last() + this.FindDefinitionColumn; + if (this.Host.Program.LineLocs.Count - file.Line - 1 == this.FindNameLine && file.Filename == this.FindNameFilename) { + int loc = this.Host.Program.LineLocs.Last() + this.FindNameColumn; return loc >= this.TokenLoc && loc <= this.Loc; } return false; @@ -212,8 +196,8 @@ public class FuParser : FuLexer bool ParseName!(FuName! result) { - if (IsFindDefinition()) - this.FoundDefinition = result; + if (IsFindName()) + this.FoundName = result; result.Loc = this.TokenLoc; result.Name = this.StringValue; return Expect(FuToken.Id); @@ -1056,7 +1040,7 @@ public class FuParser : FuLexer continue; } - bool foundDefinition = IsFindDefinition(); + bool foundName = IsFindName(); int loc = this.TokenLoc; string() name = this.StringValue; if (!Expect(FuToken.Id)) @@ -1088,8 +1072,8 @@ public class FuParser : FuLexer FuMethod# method = new FuMethod { StartLine = line, StartColumn = column, Loc = loc, Documentation = doc, Visibility = visibility, CallType = callType, TypeExpr = type, Name = name }; ParseMethod(klass, method); - if (foundDefinition) - this.FoundDefinition = method; + if (foundName) + this.FoundName = method; continue; } @@ -1104,8 +1088,8 @@ public class FuParser : FuLexer Visibility = visibility, TypeExpr = type, Name = name, Value = ParseInitializer() }; AddSymbol(klass, field); CloseMember(FuToken.Semicolon, field); - if (foundDefinition) - this.FoundDefinition = field; + if (foundName) + this.FoundName = field; } CloseContainer(klass); } diff --git a/SymbolReferenceVisitor.fu b/SymbolReferenceVisitor.fu new file mode 100644 index 00000000..3c9e618e --- /dev/null +++ b/SymbolReferenceVisitor.fu @@ -0,0 +1,292 @@ +// SymbolReferenceVisitor.fu - visitor of symbol references +// +// Copyright (C) 2024 Piotr Fusik +// +// This file is part of Fusion Transpiler, +// see https://github.com/fusionlanguage/fut +// +// Fusion Transpiler is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Fusion Transpiler is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Fusion Transpiler. If not, see http://www.gnu.org/licenses/ + +public abstract class FuSymbolReferenceVisitor : FuVisitor +{ + FuSymbol Symbol; + + protected abstract void VisitFound(FuStatement reference); + + void VisitReference(FuStatement reference, FuSymbol symbol) + { + if (symbol == this.Symbol) + VisitFound(reference); + } + + void VisitType(FuType type) + { + if (type is FuClassType klass) { + VisitReference(klass, klass.Class); + if (klass.TypeArg0 != null) { + VisitType(klass.TypeArg0); + if (klass.TypeArg1 != null) + VisitType(klass.TypeArg1); + } + } + } + + internal override void VisitConst!(FuConst statement) + { + VisitType(statement.Type); + statement.Value.Accept(this, FuPriority.Statement); + } + + internal override void VisitExpr!(FuExpr expr) + { + expr.Accept(this, FuPriority.Statement); + } + + void VisitStatements!(List statements) + { + foreach (FuStatement statement in statements) + statement.AcceptStatement(this); + } + + internal override void VisitBlock!(FuBlock block) + { + VisitStatements(block.Statements); + } + + internal override void VisitAssert!(FuAssert statement) + { + statement.Cond.Accept(this, FuPriority.Statement); + VisitOptionalStatement(statement.Message); + } + + internal override void VisitBreak!(FuBreak statement) + { + } + + internal override void VisitContinue!(FuContinue statement) + { + } + + internal override void VisitDoWhile!(FuDoWhile statement) + { + statement.Body.AcceptStatement(this); + statement.Cond.Accept(this, FuPriority.Statement); + } + + internal override void VisitFor!(FuFor statement) + { + VisitOptionalStatement(statement.Init); + VisitOptionalStatement(statement.Cond); + VisitOptionalStatement(statement.Advance); + statement.Body.AcceptStatement(this); + } + + internal override void VisitForeach!(FuForeach statement) + { + FuVar element = statement.GetVar(); + VisitType(element.Type); + if (element.Next != null) + VisitType(element.Next.Type); + statement.Collection.Accept(this, FuPriority.Statement); + statement.Body.AcceptStatement(this); + } + + internal override void VisitIf!(FuIf statement) + { + statement.Cond.Accept(this, FuPriority.Statement); + statement.OnTrue.AcceptStatement(this); + VisitOptionalStatement(statement.OnFalse); + } + + internal override void VisitLock!(FuLock statement) + { + statement.Lock.Accept(this, FuPriority.Statement); + statement.Body.AcceptStatement(this); + } + + internal override void VisitNative!(FuNative statement) + { + } + + internal override void VisitReturn!(FuReturn statement) + { + VisitOptionalStatement(statement.Value); + } + + internal override void VisitSwitch!(FuSwitch statement) + { + statement.Value.Accept(this, FuPriority.Statement); + foreach (FuCase kase in statement.Cases) { + foreach (FuExpr value in kase.Values) + value.Accept(this, FuPriority.Statement); + VisitStatements(kase.Body); + } + VisitStatements(statement.DefaultBody); + } + + internal override void VisitThrow!(FuThrow statement) + { + VisitSymbolReference(statement.Class, FuPriority.Statement); + VisitOptionalStatement(statement.Message); + } + + internal override void VisitWhile!(FuWhile statement) + { + statement.Cond.Accept(this, FuPriority.Statement); + statement.Body.AcceptStatement(this); + } + + internal override void VisitEnumValue!(FuConst konst, FuConst? previous) + { + assert false; + } + + internal override void VisitLiteralNull!() + { + } + + internal override void VisitLiteralFalse!() + { + } + + internal override void VisitLiteralTrue!() + { + } + + internal override void VisitLiteralLong!(long value) + { + } + + internal override void VisitLiteralChar!(int value) + { + } + + internal override void VisitLiteralDouble!(double value) + { + } + + internal override void VisitLiteralString!(string value) + { + } + + internal override void VisitAggregateInitializer!(FuAggregateInitializer expr) + { + foreach (FuExpr item in expr.Items) + item.Accept(this, FuPriority.Statement); + } + + internal override void VisitInterpolatedString!(FuInterpolatedString expr, FuPriority parent) + { + foreach (FuInterpolatedPart part in expr.Parts) { + part.Argument.Accept(this, FuPriority.Statement); + VisitOptionalStatement(part.WidthExpr); + } + } + + internal override void VisitSymbolReference!(FuSymbolReference expr, FuPriority parent) + { + VisitReference(expr, expr.Symbol); + } + + internal override void VisitPrefixExpr!(FuPrefixExpr expr, FuPriority parent) + { + if (expr.Op == FuToken.New) + VisitType(expr.Type); + VisitOptionalStatement(expr.Inner); + } + + internal override void VisitPostfixExpr!(FuPostfixExpr expr, FuPriority parent) + { + expr.Inner.Accept(this, FuPriority.Statement); + } + + internal override void VisitBinaryExpr!(FuBinaryExpr expr, FuPriority parent) + { + expr.Left.Accept(this, FuPriority.Statement); + expr.Right.Accept(this, FuPriority.Statement); + } + + internal override void VisitSelectExpr!(FuSelectExpr expr, FuPriority parent) + { + expr.Cond.Accept(this, FuPriority.Statement); + expr.OnTrue.Accept(this, FuPriority.Statement); + expr.OnFalse.Accept(this, FuPriority.Statement); + } + + internal override void VisitCallExpr!(FuCallExpr expr, FuPriority parent) + { + VisitSymbolReference(expr.Method, FuPriority.Statement); + foreach (FuExpr arg in expr.Arguments) + arg.Accept(this, FuPriority.Statement); + } + + internal override void VisitLambdaExpr!(FuLambdaExpr expr) + { + expr.Body.Accept(this, FuPriority.Statement); + } + + internal override void VisitVar!(FuVar expr) + { + VisitType(expr.Type); + VisitOptionalStatement(expr.Value); + } + + void VisitClass!(FuClass klass) + { + if (klass.HasBaseClass()) + VisitSymbolReference(klass.BaseClass, FuPriority.Statement); + if (klass.Constructor != null) + klass.Constructor.Body.AcceptStatement(this); + for (FuSymbol? symbol = klass.First; symbol != null; symbol = symbol.Next) { + VisitType(symbol.Type); + switch (symbol) { + case FuConst konst: + konst.Value.Accept(this, FuPriority.Statement); + break; + case FuField field: + VisitOptionalStatement(field.Value); + break; + case FuMethod method: + for (FuVar? param = method.FirstParameter(); param != null; param = param.NextVar()) + VisitVar(param); + foreach (FuThrowsDeclaration decl in method.Throws) + VisitSymbolReference(decl, FuPriority.Statement); + VisitOptionalStatement(method.Body); + break; + default: + assert false; + } + } + } + + public void FindReferences!(FuProgram program, FuSymbol symbol) + { + this.Symbol = symbol; + for (FuSymbol? type = program.First; type != null; type = type.Next) { + switch (type) { + case FuClass klass: + VisitClass(klass); + break; + case FuEnum enu: + for (FuSymbol? symbol = enu.First; symbol != null; symbol = symbol.Next) { + if (symbol is FuConst konst && !(konst.Value is FuImplicitEnumValue)) + konst.Value.Accept(this, FuPriority.Statement); + } + break; + default: + assert false; + } + } + } +} diff --git a/editors/vscode/Makefile b/editors/vscode/Makefile index f50db131..4c834655 100644 --- a/editors/vscode/Makefile +++ b/editors/vscode/Makefile @@ -6,7 +6,7 @@ run: fusion-$(VERSION).vsix fusion-$(VERSION).vsix: package.json fu-logo.png fu-file.svg language-configuration.json tsconfig.json syntaxes/fusion.tmLanguage.json src/extension.ts src/fucheck.js node_modules vsce package -src/fucheck.js: ../../Lexer.fu ../../AST.fu ../../Parser.fu ../../Sema.fu +src/fucheck.js: ../../Lexer.fu ../../AST.fu ../../Parser.fu ../../Sema.fu ../../SymbolReferenceVisitor.fu fut -o $@ $^ node_modules: package.json diff --git a/editors/vscode/README.md b/editors/vscode/README.md index 4ef7ebeb..6935e0b5 100644 --- a/editors/vscode/README.md +++ b/editors/vscode/README.md @@ -4,6 +4,7 @@ A Visual Studio Code extension for the [Fusion programming language](https://fus * Error highlighting * Outline * Go to definition +* Go to references, Find all references * Snippets Fusion is a language designed to be translated automatically to diff --git a/editors/vscode/src/extension.ts b/editors/vscode/src/extension.ts index 32fc5a00..94f80910 100644 --- a/editors/vscode/src/extension.ts +++ b/editors/vscode/src/extension.ts @@ -19,7 +19,7 @@ // along with Fusion Transpiler. If not, see http://www.gnu.org/licenses/ import * as vscode from "vscode"; -import { FuParser, FuProgram, FuSystem, FuSema, FuSemaHost, FuContainerType, FuEnum, FuMember, FuField, FuMethod } from "./fucheck.js"; +import { FuParser, FuProgram, FuSystem, FuSema, FuSemaHost, FuSymbolReferenceVisitor, FuStatement, FuSymbol, FuContainerType, FuEnum, FuMember, FuField, FuMethod } from "./fucheck.js"; class VsCodeHost extends FuSemaHost { @@ -73,6 +73,29 @@ class VsCodeHost extends FuSemaHost sema.setHost(this); sema.process(); } + + async findSymbol(document: vscode.TextDocument, position: vscode.Position): Promise + { + const parser = this.createParser(); + const filename = document.uri.toString(); + parser.findName(filename, position.line, position.character); + const files = await vscode.workspace.findFiles("*.fu"); + if (files.some(uri => uri.toString() == filename)) + await this.parseFolder(files, parser); + else + this.parseDocument(document, parser); + this.doSema(); + return parser.getFoundDefinition(); + } + + toLocation(statement: FuStatement): vscode.Location | null + { + if (statement.loc <= 0) + return null; + const line = this.program.getLine(statement.loc); + const file = this.program.getSourceFile(line); + return new vscode.Location(vscode.Uri.parse(file.filename), new vscode.Position(line - file.line, statement.loc - this.program.lineLocs[line])); + } } class VsCodeDiagnostics extends VsCodeHost @@ -119,7 +142,7 @@ class VsCodeDiagnostics extends VsCodeHost this.#diagnostics.clear(); } - check(document: vscode.TextDocument) + check(document: vscode.TextDocument): void { if (document.languageId != "fusion") return; @@ -129,7 +152,7 @@ class VsCodeDiagnostics extends VsCodeHost this.#timeoutId = setTimeout(() => this.#process(), 1000); } - delete(document: vscode.TextDocument) + delete(document: vscode.TextDocument): void { this.#queue.delete(document.uri.toString()); this.#diagnosticCollection.delete(document.uri); @@ -140,17 +163,40 @@ class VsCodeDefinitionProvider extends VsCodeHost { async findDefinition(document: vscode.TextDocument, position: vscode.Position): Promise { - const parser = this.createParser(); - const filename = document.uri.toString(); - parser.findDefinition(filename, position.line, position.character); - const files = await vscode.workspace.findFiles("*.fu"); - if (files.some(uri => uri.toString() == filename)) - await this.parseFolder(files, parser); - else - this.parseDocument(document, parser); - this.doSema(); - const definitionFilename: string | null = parser.getFoundDefinitionFilename(); - return definitionFilename == null ? null : new vscode.Location(vscode.Uri.parse(definitionFilename), new vscode.Position(parser.getFoundDefinitionLine(), parser.getFoundDefinitionColumn())); + const symbol = await this.findSymbol(document, position); + return symbol == null ? null : this.toLocation(symbol); + } +} + +class VsCodeReferenceCollector extends FuSymbolReferenceVisitor +{ + host: VsCodeHost; + result: vscode.Location[] = []; + + constructor(host: VsCodeHost) + { + super(); + this.host = host; + } + + visitFound(reference: FuStatement): void + { + const location = this.host.toLocation(reference); + if (location != null) + this.result.push(location); + } +} + +class VsCodeReferenceProvider extends VsCodeHost +{ + async findReferences(document: vscode.TextDocument, position: vscode.Position): Promise + { + const symbol = await this.findSymbol(document, position); + if (symbol == null) + return []; + const collector = new VsCodeReferenceCollector(this); + collector.findReferences(this.program, symbol); + return collector.result; } } @@ -207,6 +253,11 @@ export function activate(context: vscode.ExtensionContext): void return new VsCodeDefinitionProvider().findDefinition(document, position); } }); + vscode.languages.registerReferenceProvider("fusion", { + provideReferences(document, position, context, token) { + return new VsCodeReferenceProvider().findReferences(document, position); + } + }); vscode.languages.registerDocumentSymbolProvider("fusion", { provideDocumentSymbols(document, token) { return new VsCodeSymbolProvider().provideSymbols(document); diff --git a/libfut.cpp b/libfut.cpp index 0a517d01..c0684569 100644 --- a/libfut.cpp +++ b/libfut.cpp @@ -2990,36 +2990,17 @@ const FuSourceFile * FuProgram::getSourceFile(int line) const return &this->sourceFiles[l]; } -void FuParser::findDefinition(std::string_view filename, int line, int column) +void FuParser::findName(std::string_view filename, int line, int column) { - this->findDefinitionFilename = filename; - this->findDefinitionLine = line; - this->findDefinitionColumn = column; - this->foundDefinition = nullptr; + this->findNameFilename = filename; + this->findNameLine = line; + this->findNameColumn = column; + this->foundName = nullptr; } -std::string_view FuParser::getFoundDefinitionFilename() +const FuSymbol * FuParser::getFoundDefinition() const { - if (this->foundDefinition == nullptr || this->foundDefinition->getSymbol() == nullptr) - return std::string_view(); - int loc = this->foundDefinition->getSymbol()->loc; - if (loc <= 0) - return std::string_view(); - int line = this->host->program->getLine(loc); - const FuSourceFile * file = this->host->program->getSourceFile(line); - this->findDefinitionLine = line - file->line; - this->findDefinitionColumn = loc - this->host->program->lineLocs[line]; - return file->filename; -} - -int FuParser::getFoundDefinitionLine() const -{ - return this->findDefinitionLine; -} - -int FuParser::getFoundDefinitionColumn() const -{ - return this->findDefinitionColumn; + return this->foundName == nullptr ? nullptr : this->foundName->getSymbol(); } bool FuParser::docParseLine(FuDocPara * para) @@ -3188,11 +3169,11 @@ std::shared_ptr FuParser::parseParenthesized() return result; } -bool FuParser::isFindDefinition() const +bool FuParser::isFindName() const { const FuSourceFile * file = &static_cast(this->host->program->sourceFiles.back()); - if (std::ssize(this->host->program->lineLocs) - file->line - 1 == this->findDefinitionLine && file->filename == this->findDefinitionFilename) { - int loc = this->host->program->lineLocs.back() + this->findDefinitionColumn; + if (std::ssize(this->host->program->lineLocs) - file->line - 1 == this->findNameLine && file->filename == this->findNameFilename) { + int loc = this->host->program->lineLocs.back() + this->findNameColumn; return loc >= this->tokenLoc && loc <= this->loc; } return false; @@ -3200,8 +3181,8 @@ bool FuParser::isFindDefinition() const bool FuParser::parseName(FuName * result) { - if (isFindDefinition()) - this->foundDefinition = result; + if (isFindName()) + this->foundName = result; result->loc = this->tokenLoc; result->name = this->stringValue; return expect(FuToken::id); @@ -4253,7 +4234,7 @@ void FuParser::parseClass(std::shared_ptr doc, int line, int column, klass->constructor->body = parseBlock(klass->constructor.get()); continue; } - bool foundDefinition = isFindDefinition(); + bool foundName = isFindName(); int loc = this->tokenLoc; std::string name{this->stringValue}; if (!expect(FuToken::id)) @@ -4279,8 +4260,8 @@ void FuParser::parseClass(std::shared_ptr doc, int line, int column, method->typeExpr = type; method->name = name; parseMethod(klass.get(), method); - if (foundDefinition) - this->foundDefinition = method.get(); + if (foundName) + this->foundName = method.get(); continue; } if (visibility == FuVisibility::public_) @@ -4300,8 +4281,8 @@ void FuParser::parseClass(std::shared_ptr doc, int line, int column, field->value = parseInitializer(); addSymbol(klass.get(), field); closeMember(FuToken::semicolon, field.get()); - if (foundDefinition) - this->foundDefinition = field.get(); + if (foundName) + this->foundName = field.get(); } closeContainer(klass.get()); } diff --git a/libfut.cs b/libfut.cs index d0c0d32f..f671d7ed 100644 --- a/libfut.cs +++ b/libfut.cs @@ -3496,39 +3496,23 @@ public class FuParser : FuLexer FuCondCompletionStatement CurrentLoopOrSwitch = null; - string FindDefinitionFilename; + string FindNameFilename; - int FindDefinitionLine = -1; + int FindNameLine = -1; - int FindDefinitionColumn; + int FindNameColumn; - FuName FoundDefinition = null; + FuName FoundName = null; - public void FindDefinition(string filename, int line, int column) + public void FindName(string filename, int line, int column) { - this.FindDefinitionFilename = filename; - this.FindDefinitionLine = line; - this.FindDefinitionColumn = column; - this.FoundDefinition = null; + this.FindNameFilename = filename; + this.FindNameLine = line; + this.FindNameColumn = column; + this.FoundName = null; } - public string GetFoundDefinitionFilename() - { - if (this.FoundDefinition == null || this.FoundDefinition.GetSymbol() == null) - return null; - int loc = this.FoundDefinition.GetSymbol().Loc; - if (loc <= 0) - return null; - int line = this.Host.Program.GetLine(loc); - FuSourceFile file = this.Host.Program.GetSourceFile(line); - this.FindDefinitionLine = line - file.Line; - this.FindDefinitionColumn = loc - this.Host.Program.LineLocs[line]; - return file.Filename; - } - - public int GetFoundDefinitionLine() => this.FindDefinitionLine; - - public int GetFoundDefinitionColumn() => this.FindDefinitionColumn; + public FuSymbol GetFoundDefinition() => this.FoundName == null ? null : this.FoundName.GetSymbol(); bool DocParseLine(FuDocPara para) { @@ -3679,11 +3663,11 @@ FuExpr ParseParenthesized() return result; } - bool IsFindDefinition() + bool IsFindName() { FuSourceFile file = this.Host.Program.SourceFiles[^1]; - if (this.Host.Program.LineLocs.Count - file.Line - 1 == this.FindDefinitionLine && file.Filename == this.FindDefinitionFilename) { - int loc = this.Host.Program.LineLocs[^1] + this.FindDefinitionColumn; + if (this.Host.Program.LineLocs.Count - file.Line - 1 == this.FindNameLine && file.Filename == this.FindNameFilename) { + int loc = this.Host.Program.LineLocs[^1] + this.FindNameColumn; return loc >= this.TokenLoc && loc <= this.Loc; } return false; @@ -3691,8 +3675,8 @@ bool IsFindDefinition() bool ParseName(FuName result) { - if (IsFindDefinition()) - this.FoundDefinition = result; + if (IsFindName()) + this.FoundName = result; result.Loc = this.TokenLoc; result.Name = this.StringValue; return Expect(FuToken.Id); @@ -4529,7 +4513,7 @@ void ParseClass(FuCodeDoc doc, int line, int column, bool isPublic, FuCallType c klass.Constructor.Body = ParseBlock(klass.Constructor); continue; } - bool foundDefinition = IsFindDefinition(); + bool foundName = IsFindName(); int loc = this.TokenLoc; string name = this.StringValue; if (!Expect(FuToken.Id)) @@ -4547,8 +4531,8 @@ void ParseClass(FuCodeDoc doc, int line, int column, bool isPublic, FuCallType c ReportCallTypeError(callTypeLine, callTypeColumn, "Private method", callType); FuMethod method = new FuMethod { StartLine = line, StartColumn = column, Loc = loc, Documentation = doc, Visibility = visibility, CallType = callType, TypeExpr = type, Name = name }; ParseMethod(klass, method); - if (foundDefinition) - this.FoundDefinition = method; + if (foundName) + this.FoundName = method; continue; } if (visibility == FuVisibility.Public) @@ -4560,8 +4544,8 @@ void ParseClass(FuCodeDoc doc, int line, int column, bool isPublic, FuCallType c FuField field = new FuField { StartLine = line, StartColumn = column, Loc = loc, Documentation = doc, Visibility = visibility, TypeExpr = type, Name = name, Value = ParseInitializer() }; AddSymbol(klass, field); CloseMember(FuToken.Semicolon, field); - if (foundDefinition) - this.FoundDefinition = field; + if (foundName) + this.FoundName = field; } CloseContainer(klass); } diff --git a/libfut.hpp b/libfut.hpp index d6e468dd..a35396fb 100644 --- a/libfut.hpp +++ b/libfut.hpp @@ -1576,19 +1576,17 @@ class FuParser : public FuLexer { public: FuParser() = default; - void findDefinition(std::string_view filename, int line, int column); - std::string_view getFoundDefinitionFilename(); - int getFoundDefinitionLine() const; - int getFoundDefinitionColumn() const; + void findName(std::string_view filename, int line, int column); + const FuSymbol * getFoundDefinition() const; void parse(std::string_view filename, uint8_t const * input, int inputLength); private: std::string_view xcrementParent = std::string_view(); const FuLoop * currentLoop = nullptr; FuCondCompletionStatement * currentLoopOrSwitch = nullptr; - std::string findDefinitionFilename; - int findDefinitionLine = -1; - int findDefinitionColumn; - const FuName * foundDefinition = nullptr; + std::string findNameFilename; + int findNameLine = -1; + int findNameColumn; + const FuName * foundName = nullptr; bool docParseLine(FuDocPara * para); void docParsePara(FuDocPara * para); std::shared_ptr parseDoc(); @@ -1597,7 +1595,7 @@ class FuParser : public FuLexer bool seeDigit() const; std::shared_ptr parseInterpolatedString(); std::shared_ptr parseParenthesized(); - bool isFindDefinition() const; + bool isFindName() const; bool parseName(FuName * result); void parseCollection(std::vector> * result, FuToken closing); std::shared_ptr parsePrimaryExpr(bool type); diff --git a/libfut.js b/libfut.js index 163feb9d..84138ec0 100644 --- a/libfut.js +++ b/libfut.js @@ -3694,41 +3694,22 @@ export class FuParser extends FuLexer #xcrementParent = null; #currentLoop = null; #currentLoopOrSwitch = null; - #findDefinitionFilename; - #findDefinitionLine = -1; - #findDefinitionColumn; - #foundDefinition = null; + #findNameFilename; + #findNameLine = -1; + #findNameColumn; + #foundName = null; - findDefinition(filename, line, column) + findName(filename, line, column) { - this.#findDefinitionFilename = filename; - this.#findDefinitionLine = line; - this.#findDefinitionColumn = column; - this.#foundDefinition = null; + this.#findNameFilename = filename; + this.#findNameLine = line; + this.#findNameColumn = column; + this.#foundName = null; } - getFoundDefinitionFilename() + getFoundDefinition() { - if (this.#foundDefinition == null || this.#foundDefinition.getSymbol() == null) - return null; - let loc = this.#foundDefinition.getSymbol().loc; - if (loc <= 0) - return null; - let line = this.host.program.getLine(loc); - let file = this.host.program.getSourceFile(line); - this.#findDefinitionLine = line - file.line; - this.#findDefinitionColumn = loc - this.host.program.lineLocs[line]; - return file.filename; - } - - getFoundDefinitionLine() - { - return this.#findDefinitionLine; - } - - getFoundDefinitionColumn() - { - return this.#findDefinitionColumn; + return this.#foundName == null ? null : this.#foundName.getSymbol(); } #docParseLine(para) @@ -3880,11 +3861,11 @@ export class FuParser extends FuLexer return result; } - #isFindDefinition() + #isFindName() { let file = this.host.program.sourceFiles.at(-1); - if (this.host.program.lineLocs.length - file.line - 1 == this.#findDefinitionLine && file.filename == this.#findDefinitionFilename) { - let loc = this.host.program.lineLocs.at(-1) + this.#findDefinitionColumn; + if (this.host.program.lineLocs.length - file.line - 1 == this.#findNameLine && file.filename == this.#findNameFilename) { + let loc = this.host.program.lineLocs.at(-1) + this.#findNameColumn; return loc >= this.tokenLoc && loc <= this.loc; } return false; @@ -3892,8 +3873,8 @@ export class FuParser extends FuLexer #parseName(result) { - if (this.#isFindDefinition()) - this.#foundDefinition = result; + if (this.#isFindName()) + this.#foundName = result; result.loc = this.tokenLoc; result.name = this.stringValue; return this.expect(FuToken.ID); @@ -4739,7 +4720,7 @@ export class FuParser extends FuLexer klass.constructor_.body = this.#parseBlock(klass.constructor_); continue; } - let foundDefinition = this.#isFindDefinition(); + let foundName = this.#isFindName(); let loc = this.tokenLoc; let name = this.stringValue; if (!this.expect(FuToken.ID)) @@ -4757,8 +4738,8 @@ export class FuParser extends FuLexer this.#reportCallTypeError(callTypeLine, callTypeColumn, "Private method", callType); let method = Object.assign(new FuMethod(), { startLine: line, startColumn: column, loc: loc, documentation: doc, visibility: visibility, callType: callType, typeExpr: type, name: name }); this.#parseMethod(klass, method); - if (foundDefinition) - this.#foundDefinition = method; + if (foundName) + this.#foundName = method; continue; } if (visibility == FuVisibility.PUBLIC) @@ -4770,8 +4751,8 @@ export class FuParser extends FuLexer let field = Object.assign(new FuField(), { startLine: line, startColumn: column, loc: loc, documentation: doc, visibility: visibility, typeExpr: type, name: name, value: this.#parseInitializer() }); this.#addSymbol(klass, field); this.#closeMember(FuToken.SEMICOLON, field); - if (foundDefinition) - this.#foundDefinition = field; + if (foundName) + this.#foundName = field; } this.#closeContainer(klass); }