From 645186a510a7d0949066931d9cad54bff7644549 Mon Sep 17 00:00:00 2001 From: Piotr Fusik Date: Sat, 20 Apr 2024 14:25:29 +0200 Subject: [PATCH] [vscode] Go to definition jumps to the start of definition. Instead of "No definition found". --- AST.fu | 3 +++ Parser.fu | 48 ++++++++++++++++++++++++++------------------- libfut.cpp | 57 ++++++++++++++++++++++++++++++++++-------------------- libfut.cs | 55 +++++++++++++++++++++++++++++++++------------------- libfut.hpp | 8 ++++++-- libfut.js | 57 ++++++++++++++++++++++++++++++++++++------------------ 6 files changed, 146 insertions(+), 82 deletions(-) diff --git a/AST.fu b/AST.fu index bb21f5ae..fb2866d6 100644 --- a/AST.fu +++ b/AST.fu @@ -339,6 +339,7 @@ public abstract class FuName : FuExpr { internal string() Name = ""; public override int GetLocLength() => this.Name.Length; + public abstract FuSymbol? GetSymbol(); } public abstract class FuSymbol : FuName @@ -347,6 +348,7 @@ public abstract class FuSymbol : FuName internal FuSymbol!? Next; internal FuScope!? Parent; internal FuCodeDoc#? Documentation = null; + public override FuSymbol? GetSymbol() => this; public override string() ToString() => this.Name; } @@ -592,6 +594,7 @@ public class FuSymbolReference : FuName public override void Accept(FuVisitor! visitor, FuPriority parent) { visitor.VisitSymbolReference(this, parent); } public override bool IsReferenceTo(FuSymbol symbol) => this.Symbol == symbol; public override bool IsNewString(bool substringOffset) => this.Symbol.Id == FuId.MatchValue; + public override FuSymbol? GetSymbol() => this.Symbol; public override string() ToString() => this.Left != null ? $"{this.Left}.{this.Name}" : this.Name; } diff --git a/Parser.fu b/Parser.fu index 9b5c7dfb..1f815a16 100644 --- a/Parser.fu +++ b/Parser.fu @@ -27,7 +27,7 @@ public class FuParser : FuLexer string() FindDefinitionFilename; int FindDefinitionLine = -1; int FindDefinitionColumn; - FuSymbolReference? FoundDefinition = null; + FuName? FoundDefinition = null; public void FindDefinition!(string filename, int line, int column) { @@ -39,9 +39,9 @@ public class FuParser : FuLexer public string? GetFoundDefinitionFilename!() { - if (this.FoundDefinition == null || this.FoundDefinition.Symbol == null) + if (this.FoundDefinition == null || this.FoundDefinition.GetSymbol() == null) return null; - int loc = this.FoundDefinition.Symbol.Loc; + int loc = this.FoundDefinition.GetSymbol().Loc; if (loc <= 0) return null; int line = this.Host.Program.GetLine(loc); @@ -200,18 +200,23 @@ public class FuParser : FuLexer return result; } - void ParseSymbolReference!(FuSymbolReference! result) + bool IsFindDefinition() { 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 (loc >= this.TokenLoc && loc <= this.Loc) - this.FoundDefinition = result; + return loc >= this.TokenLoc && loc <= this.Loc; } + return false; + } + bool ParseName!(FuName! result) + { + if (IsFindDefinition()) + this.FoundDefinition = result; result.Loc = this.TokenLoc; result.Name = this.StringValue; - Expect(FuToken.Id); + return Expect(FuToken.Id); } void ParseCollection!(List! result, FuToken closing) @@ -278,7 +283,7 @@ public class FuParser : FuLexer break; case FuToken.Id: FuSymbolReference# symbol = new FuSymbolReference(); - ParseSymbolReference(symbol); + ParseName(symbol); if (Eat(FuToken.FatArrow)) { FuLambdaExpr# lambda = new FuLambdaExpr { Loc = symbol.Loc }; lambda.Add(FuVar.New(null, symbol.Name)); @@ -323,7 +328,7 @@ public class FuParser : FuLexer case FuToken.Dot: NextToken(); FuSymbolReference# path = new FuSymbolReference { Left = result }; - ParseSymbolReference(path); + ParseName(path); result = path; break; case FuToken.LeftParenthesis: @@ -514,7 +519,7 @@ public class FuParser : FuLexer do { int loc = this.TokenLoc; FuSymbolReference# field = new FuSymbolReference(); - ParseSymbolReference(field); + ParseName(field); Expect(FuToken.Assign); result.Items.Add(new FuBinaryExpr { Loc = loc, Left = field, Op = FuToken.Assign, Right = ParseExpr() }); } while (Eat(FuToken.Comma)); @@ -836,7 +841,7 @@ public class FuParser : FuLexer FuThrow# result = new FuThrow { Loc = this.TokenLoc }; Expect(FuToken.Throw); result.Class = new FuSymbolReference(); - ParseSymbolReference(result.Class); + ParseName(result.Class); ExpectOrSkip(FuToken.LeftParenthesis); result.Message = See(FuToken.RightParenthesis) ? null : ParseExpr(); Expect(FuToken.RightParenthesis); @@ -944,7 +949,7 @@ public class FuParser : FuLexer } else decl.Documentation = throwsDoc; - ParseSymbolReference(decl); + ParseName(decl); method.Throws.Add(decl); } while (Eat(FuToken.Comma)); } @@ -982,11 +987,11 @@ public class FuParser : FuLexer void ParseClass!(FuCodeDoc# doc, int line, int column, bool isPublic, FuCallType callType) { Expect(FuToken.Class); - FuClass# klass = new FuClass { Loc = this.TokenLoc, Documentation = doc, StartLine = line, StartColumn = column, IsPublic = isPublic, CallType = callType, Name = this.StringValue }; - if (Expect(FuToken.Id)) + FuClass# klass = new FuClass { Documentation = doc, StartLine = line, StartColumn = column, IsPublic = isPublic, CallType = callType }; + if (ParseName(klass)) AddSymbol(this.Host.Program, klass); if (Eat(FuToken.Colon)) - ParseSymbolReference(klass.BaseClass); + ParseName(klass.BaseClass); Expect(FuToken.LeftBrace); while (!See(FuToken.RightBrace) && !See(FuToken.EndOfFile)) { @@ -1051,6 +1056,7 @@ public class FuParser : FuLexer continue; } + bool foundDefinition = IsFindDefinition(); int loc = this.TokenLoc; string() name = this.StringValue; if (!Expect(FuToken.Id)) @@ -1082,6 +1088,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; continue; } @@ -1096,6 +1104,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; } CloseContainer(klass); } @@ -1108,17 +1118,15 @@ public class FuParser : FuLexer enu.Documentation = doc; enu.StartLine = line; enu.StartColumn = column; - enu.Loc = this.TokenLoc; enu.IsPublic = isPublic; - enu.Name = this.StringValue; - if (Expect(FuToken.Id)) + if (ParseName(enu)) AddSymbol(this.Host.Program, enu); Expect(FuToken.LeftBrace); do { - FuConst# konst = new FuConst { Visibility = FuVisibility.Public, Documentation = ParseDoc(), Loc = this.TokenLoc, Name = this.StringValue, Type = enu, VisitStatus = FuVisitStatus.NotYet }; + FuConst# konst = new FuConst { Visibility = FuVisibility.Public, Documentation = ParseDoc(), Type = enu, VisitStatus = FuVisitStatus.NotYet }; konst.StartLine = GetCurrentLine(); konst.StartColumn = GetTokenColumn(); - Expect(FuToken.Id); + ParseName(konst); if (Eat(FuToken.Assign)) konst.Value = ParseExpr(); else if (flags) diff --git a/libfut.cpp b/libfut.cpp index 0526712f..58b5f559 100644 --- a/libfut.cpp +++ b/libfut.cpp @@ -1172,6 +1172,11 @@ int FuName::getLocLength() const return std::ssize(this->name); } +const FuSymbol * FuSymbol::getSymbol() const +{ + return this; +} + std::string FuSymbol::toString() const { return this->name; @@ -1488,6 +1493,11 @@ bool FuSymbolReference::isNewString(bool substringOffset) const return this->symbol->id == FuId::matchValue; } +const FuSymbol * FuSymbolReference::getSymbol() const +{ + return this->symbol; +} + std::string FuSymbolReference::toString() const { return std::string(this->left != nullptr ? std::format("{}.{}", this->left->toString(), this->name) : this->name); @@ -2990,9 +3000,9 @@ void FuParser::findDefinition(std::string_view filename, int line, int column) std::string_view FuParser::getFoundDefinitionFilename() { - if (this->foundDefinition == nullptr || this->foundDefinition->symbol == nullptr) + if (this->foundDefinition == nullptr || this->foundDefinition->getSymbol() == nullptr) return std::string_view(); - int loc = this->foundDefinition->symbol->loc; + int loc = this->foundDefinition->getSymbol()->loc; if (loc <= 0) return std::string_view(); int line = this->host->program->getLine(loc); @@ -3178,17 +3188,23 @@ std::shared_ptr FuParser::parseParenthesized() return result; } -void FuParser::parseSymbolReference(FuSymbolReference * result) +bool FuParser::isFindDefinition() 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 (loc >= this->tokenLoc && loc <= this->loc) - this->foundDefinition = result; + return loc >= this->tokenLoc && loc <= this->loc; } + return false; +} + +bool FuParser::parseName(FuName * result) +{ + if (isFindDefinition()) + this->foundDefinition = result; result->loc = this->tokenLoc; result->name = this->stringValue; - expect(FuToken::id); + return expect(FuToken::id); } void FuParser::parseCollection(std::vector> * result, FuToken closing) @@ -3293,7 +3309,7 @@ std::shared_ptr FuParser::parsePrimaryExpr(bool type) case FuToken::id: { std::shared_ptr symbol = std::make_shared(); - parseSymbolReference(symbol.get()); + parseName(symbol.get()); if (eat(FuToken::fatArrow)) { std::shared_ptr lambda = std::make_shared(); lambda->loc = symbol->loc; @@ -3345,7 +3361,7 @@ std::shared_ptr FuParser::parsePrimaryExpr(bool type) { std::shared_ptr path = std::make_shared(); path->left = result; - parseSymbolReference(path.get()); + parseName(path.get()); result = path; break; } @@ -3640,7 +3656,7 @@ std::shared_ptr FuParser::parseObjectLiteral() do { int loc = this->tokenLoc; std::shared_ptr field = std::make_shared(); - parseSymbolReference(field.get()); + parseName(field.get()); expect(FuToken::assign); std::shared_ptr futemp0 = std::make_shared(); futemp0->loc = loc; @@ -4008,7 +4024,7 @@ std::shared_ptr FuParser::parseThrow() result->loc = this->tokenLoc; expect(FuToken::throw_); result->class_ = std::make_shared(); - parseSymbolReference(result->class_.get()); + parseName(result->class_.get()); expectOrSkip(FuToken::leftParenthesis); result->message = see(FuToken::rightParenthesis) ? nullptr : parseExpr(); expect(FuToken::rightParenthesis); @@ -4120,7 +4136,7 @@ void FuParser::parseMethod(FuClass * klass, std::shared_ptr method) } else decl->documentation = throwsDoc; - parseSymbolReference(decl.get()); + parseName(decl.get()); method->throws.push_back(decl); } while (eat(FuToken::comma)); @@ -4166,17 +4182,15 @@ void FuParser::parseClass(std::shared_ptr doc, int line, int column, { expect(FuToken::class_); std::shared_ptr klass = std::make_shared(); - klass->loc = this->tokenLoc; klass->documentation = doc; klass->startLine = line; klass->startColumn = column; klass->isPublic = isPublic; klass->callType = callType; - klass->name = this->stringValue; - if (expect(FuToken::id)) + if (parseName(klass.get())) addSymbol(this->host->program, klass); if (eat(FuToken::colon)) - parseSymbolReference(&klass->baseClass); + parseName(&klass->baseClass); expect(FuToken::leftBrace); while (!see(FuToken::rightBrace) && !see(FuToken::endOfFile)) { doc = parseDoc(); @@ -4243,6 +4257,7 @@ void FuParser::parseClass(std::shared_ptr doc, int line, int column, klass->constructor->body = parseBlock(klass->constructor.get()); continue; } + bool foundDefinition = isFindDefinition(); int loc = this->tokenLoc; std::string name{this->stringValue}; if (!expect(FuToken::id)) @@ -4268,6 +4283,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(); continue; } if (visibility == FuVisibility::public_) @@ -4287,6 +4304,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(); } closeContainer(klass.get()); } @@ -4299,23 +4318,19 @@ void FuParser::parseEnum(std::shared_ptr doc, int line, int column, b enu->documentation = doc; enu->startLine = line; enu->startColumn = column; - enu->loc = this->tokenLoc; enu->isPublic = isPublic; - enu->name = this->stringValue; - if (expect(FuToken::id)) + if (parseName(enu.get())) addSymbol(this->host->program, enu); expect(FuToken::leftBrace); do { std::shared_ptr konst = std::make_shared(); konst->visibility = FuVisibility::public_; konst->documentation = parseDoc(); - konst->loc = this->tokenLoc; - konst->name = this->stringValue; konst->type = enu; konst->visitStatus = FuVisitStatus::notYet; konst->startLine = getCurrentLine(); konst->startColumn = getTokenColumn(); - expect(FuToken::id); + parseName(konst.get()); if (eat(FuToken::assign)) konst->value = parseExpr(); else if (flags) diff --git a/libfut.cs b/libfut.cs index f57aa263..2696b155 100644 --- a/libfut.cs +++ b/libfut.cs @@ -1623,6 +1623,8 @@ public abstract class FuName : FuExpr internal string Name = ""; public override int GetLocLength() => this.Name.Length; + + public abstract FuSymbol GetSymbol(); } public abstract class FuSymbol : FuName @@ -1636,6 +1638,8 @@ public abstract class FuSymbol : FuName internal FuCodeDoc Documentation = null; + public override FuSymbol GetSymbol() => this; + public override string ToString() => this.Name; } @@ -1944,6 +1948,8 @@ public override void Accept(FuVisitor visitor, FuPriority parent) public override bool IsNewString(bool substringOffset) => this.Symbol.Id == FuId.MatchValue; + public override FuSymbol GetSymbol() => this.Symbol; + public override string ToString() => this.Left != null ? $"{this.Left}.{this.Name}" : this.Name; } @@ -3496,7 +3502,7 @@ public class FuParser : FuLexer int FindDefinitionColumn; - FuSymbolReference FoundDefinition = null; + FuName FoundDefinition = null; public void FindDefinition(string filename, int line, int column) { @@ -3508,9 +3514,9 @@ public void FindDefinition(string filename, int line, int column) public string GetFoundDefinitionFilename() { - if (this.FoundDefinition == null || this.FoundDefinition.Symbol == null) + if (this.FoundDefinition == null || this.FoundDefinition.GetSymbol() == null) return null; - int loc = this.FoundDefinition.Symbol.Loc; + int loc = this.FoundDefinition.GetSymbol().Loc; if (loc <= 0) return null; int line = this.Host.Program.GetLine(loc); @@ -3673,17 +3679,23 @@ FuExpr ParseParenthesized() return result; } - void ParseSymbolReference(FuSymbolReference result) + bool IsFindDefinition() { 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 (loc >= this.TokenLoc && loc <= this.Loc) - this.FoundDefinition = result; + return loc >= this.TokenLoc && loc <= this.Loc; } + return false; + } + + bool ParseName(FuName result) + { + if (IsFindDefinition()) + this.FoundDefinition = result; result.Loc = this.TokenLoc; result.Name = this.StringValue; - Expect(FuToken.Id); + return Expect(FuToken.Id); } void ParseCollection(List result, FuToken closing) @@ -3750,7 +3762,7 @@ FuExpr ParsePrimaryExpr(bool type) break; case FuToken.Id: FuSymbolReference symbol = new FuSymbolReference(); - ParseSymbolReference(symbol); + ParseName(symbol); if (Eat(FuToken.FatArrow)) { FuLambdaExpr lambda = new FuLambdaExpr { Loc = symbol.Loc }; lambda.Add(FuVar.New(null, symbol.Name)); @@ -3790,7 +3802,7 @@ FuExpr ParsePrimaryExpr(bool type) case FuToken.Dot: NextToken(); FuSymbolReference path = new FuSymbolReference { Left = result }; - ParseSymbolReference(path); + ParseName(path); result = path; break; case FuToken.LeftParenthesis: @@ -3981,7 +3993,7 @@ FuAggregateInitializer ParseObjectLiteral() do { int loc = this.TokenLoc; FuSymbolReference field = new FuSymbolReference(); - ParseSymbolReference(field); + ParseName(field); Expect(FuToken.Assign); result.Items.Add(new FuBinaryExpr { Loc = loc, Left = field, Op = FuToken.Assign, Right = ParseExpr() }); } @@ -4302,7 +4314,7 @@ FuThrow ParseThrow() FuThrow result = new FuThrow { Loc = this.TokenLoc }; Expect(FuToken.Throw); result.Class = new FuSymbolReference(); - ParseSymbolReference(result.Class); + ParseName(result.Class); ExpectOrSkip(FuToken.LeftParenthesis); result.Message = See(FuToken.RightParenthesis) ? null : ParseExpr(); Expect(FuToken.RightParenthesis); @@ -4411,7 +4423,7 @@ void ParseMethod(FuClass klass, FuMethod method) } else decl.Documentation = throwsDoc; - ParseSymbolReference(decl); + ParseName(decl); method.Throws.Add(decl); } while (Eat(FuToken.Comma)); @@ -4456,11 +4468,11 @@ void ReportCallTypeError(int line, int column, string kind, FuCallType callType) void ParseClass(FuCodeDoc doc, int line, int column, bool isPublic, FuCallType callType) { Expect(FuToken.Class); - FuClass klass = new FuClass { Loc = this.TokenLoc, Documentation = doc, StartLine = line, StartColumn = column, IsPublic = isPublic, CallType = callType, Name = this.StringValue }; - if (Expect(FuToken.Id)) + FuClass klass = new FuClass { Documentation = doc, StartLine = line, StartColumn = column, IsPublic = isPublic, CallType = callType }; + if (ParseName(klass)) AddSymbol(this.Host.Program, klass); if (Eat(FuToken.Colon)) - ParseSymbolReference(klass.BaseClass); + ParseName(klass.BaseClass); Expect(FuToken.LeftBrace); while (!See(FuToken.RightBrace) && !See(FuToken.EndOfFile)) { doc = ParseDoc(); @@ -4517,6 +4529,7 @@ void ParseClass(FuCodeDoc doc, int line, int column, bool isPublic, FuCallType c klass.Constructor.Body = ParseBlock(klass.Constructor); continue; } + bool foundDefinition = IsFindDefinition(); int loc = this.TokenLoc; string name = this.StringValue; if (!Expect(FuToken.Id)) @@ -4534,6 +4547,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; continue; } if (visibility == FuVisibility.Public) @@ -4545,6 +4560,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; } CloseContainer(klass); } @@ -4557,17 +4574,15 @@ void ParseEnum(FuCodeDoc doc, int line, int column, bool isPublic) enu.Documentation = doc; enu.StartLine = line; enu.StartColumn = column; - enu.Loc = this.TokenLoc; enu.IsPublic = isPublic; - enu.Name = this.StringValue; - if (Expect(FuToken.Id)) + if (ParseName(enu)) AddSymbol(this.Host.Program, enu); Expect(FuToken.LeftBrace); do { - FuConst konst = new FuConst { Visibility = FuVisibility.Public, Documentation = ParseDoc(), Loc = this.TokenLoc, Name = this.StringValue, Type = enu, VisitStatus = FuVisitStatus.NotYet }; + FuConst konst = new FuConst { Visibility = FuVisibility.Public, Documentation = ParseDoc(), Type = enu, VisitStatus = FuVisitStatus.NotYet }; konst.StartLine = GetCurrentLine(); konst.StartColumn = GetTokenColumn(); - Expect(FuToken.Id); + ParseName(konst); if (Eat(FuToken.Assign)) konst.Value = ParseExpr(); else if (flags) diff --git a/libfut.hpp b/libfut.hpp index 050bc1a8..d6e468dd 100644 --- a/libfut.hpp +++ b/libfut.hpp @@ -693,6 +693,7 @@ class FuName : public FuExpr public: virtual ~FuName() = default; int getLocLength() const override; + virtual const FuSymbol * getSymbol() const = 0; protected: FuName() = default; public: @@ -703,6 +704,7 @@ class FuSymbol : public FuName { public: virtual ~FuSymbol() = default; + const FuSymbol * getSymbol() const override; std::string toString() const override; protected: FuSymbol() = default; @@ -877,6 +879,7 @@ class FuSymbolReference : public FuName void accept(FuVisitor * visitor, FuPriority parent) const override; bool isReferenceTo(const FuSymbol * symbol) const override; bool isNewString(bool substringOffset) const override; + const FuSymbol * getSymbol() const override; std::string toString() const override; public: std::shared_ptr left = nullptr; @@ -1585,7 +1588,7 @@ class FuParser : public FuLexer std::string findDefinitionFilename; int findDefinitionLine = -1; int findDefinitionColumn; - const FuSymbolReference * foundDefinition = nullptr; + const FuName * foundDefinition = nullptr; bool docParseLine(FuDocPara * para); void docParsePara(FuDocPara * para); std::shared_ptr parseDoc(); @@ -1594,7 +1597,8 @@ class FuParser : public FuLexer bool seeDigit() const; std::shared_ptr parseInterpolatedString(); std::shared_ptr parseParenthesized(); - void parseSymbolReference(FuSymbolReference * result); + bool isFindDefinition() const; + bool parseName(FuName * result); void parseCollection(std::vector> * result, FuToken closing); std::shared_ptr parsePrimaryExpr(bool type); std::shared_ptr parseMulExpr(); diff --git a/libfut.js b/libfut.js index eab880cc..20c57c8d 100644 --- a/libfut.js +++ b/libfut.js @@ -1560,6 +1560,11 @@ export class FuSymbol extends FuName parent; documentation = null; + getSymbol() + { + return this; + } + toString() { return this.name; @@ -1944,6 +1949,11 @@ export class FuSymbolReference extends FuName return this.symbol.id == FuId.MATCH_VALUE; } + getSymbol() + { + return this.symbol; + } + toString() { return this.left != null ? `${this.left}.${this.name}` : this.name; @@ -3699,9 +3709,9 @@ export class FuParser extends FuLexer getFoundDefinitionFilename() { - if (this.#foundDefinition == null || this.#foundDefinition.symbol == null) + if (this.#foundDefinition == null || this.#foundDefinition.getSymbol() == null) return null; - let loc = this.#foundDefinition.symbol.loc; + let loc = this.#foundDefinition.getSymbol().loc; if (loc <= 0) return null; let line = this.host.program.getLine(loc); @@ -3870,17 +3880,23 @@ export class FuParser extends FuLexer return result; } - #parseSymbolReference(result) + #isFindDefinition() { 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 (loc >= this.tokenLoc && loc <= this.loc) - this.#foundDefinition = result; + return loc >= this.tokenLoc && loc <= this.loc; } + return false; + } + + #parseName(result) + { + if (this.#isFindDefinition()) + this.#foundDefinition = result; result.loc = this.tokenLoc; result.name = this.stringValue; - this.expect(FuToken.ID); + return this.expect(FuToken.ID); } #parseCollection(result, closing) @@ -3947,7 +3963,7 @@ export class FuParser extends FuLexer break; case FuToken.ID: let symbol = new FuSymbolReference(); - this.#parseSymbolReference(symbol); + this.#parseName(symbol); if (this.eat(FuToken.FAT_ARROW)) { let lambda = Object.assign(new FuLambdaExpr(), { loc: symbol.loc }); lambda.add(FuVar.new(null, symbol.name)); @@ -3987,7 +4003,7 @@ export class FuParser extends FuLexer case FuToken.DOT: this.nextToken(); let path = Object.assign(new FuSymbolReference(), { left: result }); - this.#parseSymbolReference(path); + this.#parseName(path); result = path; break; case FuToken.LEFT_PARENTHESIS: @@ -4179,7 +4195,7 @@ export class FuParser extends FuLexer do { let loc = this.tokenLoc; let field = new FuSymbolReference(); - this.#parseSymbolReference(field); + this.#parseName(field); this.expect(FuToken.ASSIGN); result.items.push(Object.assign(new FuBinaryExpr(), { loc: loc, left: field, op: FuToken.ASSIGN, right: this.#parseExpr() })); } @@ -4507,7 +4523,7 @@ export class FuParser extends FuLexer let result = Object.assign(new FuThrow(), { loc: this.tokenLoc }); this.expect(FuToken.THROW); result.class = new FuSymbolReference(); - this.#parseSymbolReference(result.class); + this.#parseName(result.class); this.expectOrSkip(FuToken.LEFT_PARENTHESIS); result.message = this.see(FuToken.RIGHT_PARENTHESIS) ? null : this.#parseExpr(); this.expect(FuToken.RIGHT_PARENTHESIS); @@ -4616,7 +4632,7 @@ export class FuParser extends FuLexer } else decl.documentation = throwsDoc; - this.#parseSymbolReference(decl); + this.#parseName(decl); method.throws.push(decl); } while (this.eat(FuToken.COMMA)); @@ -4661,11 +4677,11 @@ export class FuParser extends FuLexer #parseClass(doc, line, column, isPublic, callType) { this.expect(FuToken.CLASS); - let klass = Object.assign(new FuClass(), { loc: this.tokenLoc, documentation: doc, startLine: line, startColumn: column, isPublic: isPublic, callType: callType, name: this.stringValue }); - if (this.expect(FuToken.ID)) + let klass = Object.assign(new FuClass(), { documentation: doc, startLine: line, startColumn: column, isPublic: isPublic, callType: callType }); + if (this.#parseName(klass)) this.#addSymbol(this.host.program, klass); if (this.eat(FuToken.COLON)) - this.#parseSymbolReference(klass.baseClass); + this.#parseName(klass.baseClass); this.expect(FuToken.LEFT_BRACE); while (!this.see(FuToken.RIGHT_BRACE) && !this.see(FuToken.END_OF_FILE)) { doc = this.#parseDoc(); @@ -4723,6 +4739,7 @@ export class FuParser extends FuLexer klass.constructor_.body = this.#parseBlock(klass.constructor_); continue; } + let foundDefinition = this.#isFindDefinition(); let loc = this.tokenLoc; let name = this.stringValue; if (!this.expect(FuToken.ID)) @@ -4740,6 +4757,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; continue; } if (visibility == FuVisibility.PUBLIC) @@ -4751,6 +4770,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; } this.#closeContainer(klass); } @@ -4763,17 +4784,15 @@ export class FuParser extends FuLexer enu.documentation = doc; enu.startLine = line; enu.startColumn = column; - enu.loc = this.tokenLoc; enu.isPublic = isPublic; - enu.name = this.stringValue; - if (this.expect(FuToken.ID)) + if (this.#parseName(enu)) this.#addSymbol(this.host.program, enu); this.expect(FuToken.LEFT_BRACE); do { - let konst = Object.assign(new FuConst(), { visibility: FuVisibility.PUBLIC, documentation: this.#parseDoc(), loc: this.tokenLoc, name: this.stringValue, type: enu, visitStatus: FuVisitStatus.NOT_YET }); + let konst = Object.assign(new FuConst(), { visibility: FuVisibility.PUBLIC, documentation: this.#parseDoc(), type: enu, visitStatus: FuVisitStatus.NOT_YET }); konst.startLine = this.#getCurrentLine(); konst.startColumn = this.#getTokenColumn(); - this.expect(FuToken.ID); + this.#parseName(konst); if (this.eat(FuToken.ASSIGN)) konst.value = this.#parseExpr(); else if (flags)