From 1b7e4663cbc199e66d9dfde77a1b8ebf70af0743 Mon Sep 17 00:00:00 2001 From: Piotr Fusik Date: Fri, 19 Apr 2024 15:12:34 +0200 Subject: [PATCH] [vscode] Go to definition of base class. --- AST.fu | 4 ++-- GenCpp.fu | 6 +++--- Parser.fu | 8 ++++---- Sema.fu | 7 ++++--- libfut.cpp | 23 ++++++++++++----------- libfut.cs | 25 +++++++++++++------------ libfut.hpp | 2 +- libfut.js | 25 +++++++++++++------------ test/error/ClassBaseUndefined.fu | 3 ++- 9 files changed, 54 insertions(+), 49 deletions(-) diff --git a/AST.fu b/AST.fu index 9aaa3f2b..0d7df65a 100644 --- a/AST.fu +++ b/AST.fu @@ -1318,10 +1318,10 @@ public class FuClass : FuContainerType internal FuCallType CallType; internal int TypeParameterCount = 0; internal bool HasSubclasses = false; - internal string() BaseClassName = ""; + internal FuSymbolReference() BaseClass; internal FuMethodBase#? Constructor; internal List() ConstArrays; - public bool HasBaseClass() => this.BaseClassName.Length > 0; + public bool HasBaseClass() => this.BaseClass.Name.Length > 0; public bool AddsVirtualMethods() { for (FuSymbol? symbol = this.First; symbol != null; symbol = symbol.Next) { diff --git a/GenCpp.fu b/GenCpp.fu index 30be1d12..397c1a3d 100644 --- a/GenCpp.fu +++ b/GenCpp.fu @@ -1757,12 +1757,12 @@ public class GenCpp : GenCCpp if (constructor) { if (klass.Id == FuId.ExceptionClass) { Write("using "); - if (klass.BaseClassName == "Exception") + if (klass.BaseClass.Name == "Exception") Write("std::runtime_error::runtime_error"); else { - Write(klass.BaseClassName); + Write(klass.BaseClass.Name); Write("::"); - Write(klass.BaseClassName); + Write(klass.BaseClass.Name); } } else { diff --git a/Parser.fu b/Parser.fu index 2ec02775..a62568f4 100644 --- a/Parser.fu +++ b/Parser.fu @@ -985,10 +985,10 @@ public class FuParser : FuLexer FuClass# klass = new FuClass { Loc = this.TokenLoc, Documentation = doc, StartLine = line, StartColumn = column, IsPublic = isPublic, CallType = callType, Name = this.StringValue }; if (Expect(FuToken.Id)) AddSymbol(this.Host.Program, klass); - if (Eat(FuToken.Colon)) { - klass.BaseClassName = this.StringValue; - Expect(FuToken.Id); - } + if (Eat(FuToken.Colon)) + ParseSymbolReference(klass.BaseClass); + else + klass.BaseClass.Name = ""; Expect(FuToken.LeftBrace); while (!See(FuToken.RightBrace) && !See(FuToken.EndOfFile)) { diff --git a/Sema.fu b/Sema.fu index bbeb9c0b..d3a1fbed 100644 --- a/Sema.fu +++ b/Sema.fu @@ -60,14 +60,15 @@ public class FuSema { if (klass.HasBaseClass()) { this.CurrentScope = klass; - if (this.Host.Program.TryLookup(klass.BaseClassName, true) is FuClass! baseClass) { + if (this.Host.Program.TryLookup(klass.BaseClass.Name, true) is FuClass! baseClass) { if (klass.IsPublic && !baseClass.IsPublic) - ReportError(klass, "Public class cannot derive from an internal class"); + ReportError(klass.BaseClass, "Public class cannot derive from an internal class"); + klass.BaseClass.Symbol = baseClass; baseClass.HasSubclasses = true; klass.Parent = baseClass; } else - ReportError(klass, $"Base class '{klass.BaseClassName}' not found"); + ReportError(klass.BaseClass, $"Base class '{klass.BaseClass.Name}' not found"); } this.Host.Program.Classes.Add(klass); } diff --git a/libfut.cpp b/libfut.cpp index 71bcd563..f0b22121 100644 --- a/libfut.cpp +++ b/libfut.cpp @@ -2326,7 +2326,7 @@ void FuEnum::acceptValues(FuVisitor * visitor) const bool FuClass::hasBaseClass() const { - return !this->baseClassName.empty(); + return !this->baseClass.name.empty(); } bool FuClass::addsVirtualMethods() const @@ -4180,10 +4180,10 @@ void FuParser::parseClass(std::shared_ptr doc, int line, int column, klass->name = this->stringValue; if (expect(FuToken::id)) addSymbol(this->host->program, klass); - if (eat(FuToken::colon)) { - klass->baseClassName = this->stringValue; - expect(FuToken::id); - } + if (eat(FuToken::colon)) + parseSymbolReference(&klass->baseClass); + else + klass->baseClass.name = ""; expect(FuToken::leftBrace); while (!see(FuToken::rightBrace) && !see(FuToken::endOfFile)) { doc = parseDoc(); @@ -4408,14 +4408,15 @@ void FuSema::resolveBase(FuClass * klass) { if (klass->hasBaseClass()) { this->currentScope = klass; - if (FuClass *baseClass = dynamic_cast(this->host->program->tryLookup(klass->baseClassName, true).get())) { + if (FuClass *baseClass = dynamic_cast(this->host->program->tryLookup(klass->baseClass.name, true).get())) { if (klass->isPublic && !baseClass->isPublic) - reportError(klass, "Public class cannot derive from an internal class"); + reportError(&klass->baseClass, "Public class cannot derive from an internal class"); + klass->baseClass.symbol = baseClass; baseClass->hasSubclasses = true; klass->parent = baseClass; } else - reportError(klass, std::format("Base class '{}' not found", klass->baseClassName)); + reportError(&klass->baseClass, std::format("Base class '{}' not found", klass->baseClass.name)); } this->host->program->classes.push_back(klass); } @@ -15063,12 +15064,12 @@ void GenCpp::writeDeclarations(const FuClass * klass, FuVisibility visibility, s if (constructor) { if (klass->id == FuId::exceptionClass) { write("using "); - if (klass->baseClassName == "Exception") + if (klass->baseClass.name == "Exception") write("std::runtime_error::runtime_error"); else { - write(klass->baseClassName); + write(klass->baseClass.name); write("::"); - write(klass->baseClassName); + write(klass->baseClass.name); } } else { diff --git a/libfut.cs b/libfut.cs index f283ffaf..a5cbe5f1 100644 --- a/libfut.cs +++ b/libfut.cs @@ -2895,13 +2895,13 @@ public class FuClass : FuContainerType internal bool HasSubclasses = false; - internal string BaseClassName = ""; + internal readonly FuSymbolReference BaseClass = new FuSymbolReference(); internal FuMethodBase Constructor; internal readonly List ConstArrays = new List(); - public bool HasBaseClass() => this.BaseClassName.Length > 0; + public bool HasBaseClass() => this.BaseClass.Name.Length > 0; public bool AddsVirtualMethods() { @@ -4459,10 +4459,10 @@ void ParseClass(FuCodeDoc doc, int line, int column, bool isPublic, FuCallType c FuClass klass = new FuClass { Loc = this.TokenLoc, Documentation = doc, StartLine = line, StartColumn = column, IsPublic = isPublic, CallType = callType, Name = this.StringValue }; if (Expect(FuToken.Id)) AddSymbol(this.Host.Program, klass); - if (Eat(FuToken.Colon)) { - klass.BaseClassName = this.StringValue; - Expect(FuToken.Id); - } + if (Eat(FuToken.Colon)) + ParseSymbolReference(klass.BaseClass); + else + klass.BaseClass.Name = ""; Expect(FuToken.LeftBrace); while (!See(FuToken.RightBrace) && !See(FuToken.EndOfFile)) { doc = ParseDoc(); @@ -4674,14 +4674,15 @@ void ResolveBase(FuClass klass) { if (klass.HasBaseClass()) { this.CurrentScope = klass; - if (this.Host.Program.TryLookup(klass.BaseClassName, true) is FuClass baseClass) { + if (this.Host.Program.TryLookup(klass.BaseClass.Name, true) is FuClass baseClass) { if (klass.IsPublic && !baseClass.IsPublic) - ReportError(klass, "Public class cannot derive from an internal class"); + ReportError(klass.BaseClass, "Public class cannot derive from an internal class"); + klass.BaseClass.Symbol = baseClass; baseClass.HasSubclasses = true; klass.Parent = baseClass; } else - ReportError(klass, $"Base class '{klass.BaseClassName}' not found"); + ReportError(klass.BaseClass, $"Base class '{klass.BaseClass.Name}' not found"); } this.Host.Program.Classes.Add(klass); } @@ -15401,12 +15402,12 @@ void WriteDeclarations(FuClass klass, FuVisibility visibility, string visibility if (constructor) { if (klass.Id == FuId.ExceptionClass) { Write("using "); - if (klass.BaseClassName == "Exception") + if (klass.BaseClass.Name == "Exception") Write("std::runtime_error::runtime_error"); else { - Write(klass.BaseClassName); + Write(klass.BaseClass.Name); Write("::"); - Write(klass.BaseClassName); + Write(klass.BaseClass.Name); } } else { diff --git a/libfut.hpp b/libfut.hpp index af0710b9..3ab20602 100644 --- a/libfut.hpp +++ b/libfut.hpp @@ -1384,7 +1384,7 @@ class FuClass : public FuContainerType FuCallType callType; int typeParameterCount = 0; bool hasSubclasses = false; - std::string baseClassName{""}; + FuSymbolReference baseClass; std::shared_ptr constructor; std::vector constArrays; }; diff --git a/libfut.js b/libfut.js index 4016d404..59ac9f40 100644 --- a/libfut.js +++ b/libfut.js @@ -3015,13 +3015,13 @@ export class FuClass extends FuContainerType callType; typeParameterCount = 0; hasSubclasses = false; - baseClassName = ""; + baseClass = new FuSymbolReference(); constructor_; constArrays = []; hasBaseClass() { - return this.baseClassName.length > 0; + return this.baseClass.name.length > 0; } addsVirtualMethods() @@ -4666,10 +4666,10 @@ export class FuParser extends FuLexer 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)) this.#addSymbol(this.host.program, klass); - if (this.eat(FuToken.COLON)) { - klass.baseClassName = this.stringValue; - this.expect(FuToken.ID); - } + if (this.eat(FuToken.COLON)) + this.#parseSymbolReference(klass.baseClass); + else + klass.baseClass.name = ""; this.expect(FuToken.LEFT_BRACE); while (!this.see(FuToken.RIGHT_BRACE) && !this.see(FuToken.END_OF_FILE)) { doc = this.#parseDoc(); @@ -4883,14 +4883,15 @@ export class FuSema if (klass.hasBaseClass()) { this.#currentScope = klass; let baseClass; - if ((baseClass = this.#host.program.tryLookup(klass.baseClassName, true)) instanceof FuClass) { + if ((baseClass = this.#host.program.tryLookup(klass.baseClass.name, true)) instanceof FuClass) { if (klass.isPublic && !baseClass.isPublic) - this.#reportError(klass, "Public class cannot derive from an internal class"); + this.#reportError(klass.baseClass, "Public class cannot derive from an internal class"); + klass.baseClass.symbol = baseClass; baseClass.hasSubclasses = true; klass.parent = baseClass; } else - this.#reportError(klass, `Base class '${klass.baseClassName}' not found`); + this.#reportError(klass.baseClass, `Base class '${klass.baseClass.name}' not found`); } this.#host.program.classes.push(klass); } @@ -15875,12 +15876,12 @@ export class GenCpp extends GenCCpp if (constructor) { if (klass.id == FuId.EXCEPTION_CLASS) { this.write("using "); - if (klass.baseClassName == "Exception") + if (klass.baseClass.name == "Exception") this.write("std::runtime_error::runtime_error"); else { - this.write(klass.baseClassName); + this.write(klass.baseClass.name); this.write("::"); - this.write(klass.baseClassName); + this.write(klass.baseClass.name); } } else { diff --git a/test/error/ClassBaseUndefined.fu b/test/error/ClassBaseUndefined.fu index 8e285084..ff3dad2f 100644 --- a/test/error/ClassBaseUndefined.fu +++ b/test/error/ClassBaseUndefined.fu @@ -1,4 +1,5 @@ -public class Test : Base //ERROR: Base class 'Base' not found +public class Test : + Base //ERROR: Base class 'Base' not found { public static bool Run() => true; }