Skip to content

Commit

Permalink
[vscode] Hovers.
Browse files Browse the repository at this point in the history
  • Loading branch information
pfusik committed Jul 29, 2024
1 parent 18a0523 commit ffc946d
Show file tree
Hide file tree
Showing 9 changed files with 146 additions and 92 deletions.
11 changes: 11 additions & 0 deletions AST.fu
Original file line number Diff line number Diff line change
Expand Up @@ -1276,6 +1276,17 @@ public class FuMethod : FuMethodBase
public override bool IsStatic() => this.CallType == FuCallType.Static;
public bool IsAbstractOrVirtual() => this.CallType == FuCallType.Abstract || this.CallType == FuCallType.Virtual;
public bool IsAbstractVirtualOrOverride() => this.CallType == FuCallType.Abstract || this.CallType == FuCallType.Virtual || this.CallType == FuCallType.Override;
public static string CallTypeToString(FuCallType callType)
{
switch (callType) {
case FuCallType.Static: return "static";
case FuCallType.Abstract: return "abstract";
case FuCallType.Virtual: return "virtual";
case FuCallType.Override: return "override";
case FuCallType.Sealed: return "sealed";
default: assert false;
}
}
public FuVar!? FirstParameter()
{
assert this.Parameters.First is FuVar! first; // FIXME: FuVar!?
Expand Down
14 changes: 1 addition & 13 deletions Parser.fu
Original file line number Diff line number Diff line change
Expand Up @@ -945,26 +945,14 @@ public class FuParser : FuLexer
method.Body = ParseBlock(method);
}

static string CallTypeToString(FuCallType callType)
{
switch (callType) {
case FuCallType.Static: return "static";
case FuCallType.Abstract: return "abstract";
case FuCallType.Virtual: return "virtual";
case FuCallType.Override: return "override";
case FuCallType.Sealed: return "sealed";
default: assert false;
}
}

void ReportFormerError(int line, int column, int length, string message)
{
this.Host.ReportError(this.Host.Program.SourceFiles.Last().Filename, line, column, column + length, message);
}

void ReportCallTypeError(int line, int column, string kind, FuCallType callType)
{
string callTypeString = CallTypeToString(callType);
string callTypeString = FuMethod.CallTypeToString(callType);
ReportFormerError(line, column, callTypeString.Length, $"{kind} cannot be {callTypeString}");
}

Expand Down
1 change: 1 addition & 0 deletions editors/vscode/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ A Visual Studio Code extension for the [Fusion programming language](https://fus
* Go to / Peek definition
* Go to / Peek / Find all implementations
* Go to / Peek / Find all references
* Hovers
* Snippets

Fusion is a language designed to be translated automatically to
Expand Down
87 changes: 68 additions & 19 deletions editors/vscode/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
// along with Fusion Transpiler. If not, see http://www.gnu.org/licenses/

import * as vscode from "vscode";
import { FuParser, FuProgram, FuSystem, FuSema, FuSemaHost, FuSymbolReferenceVisitor, FuStatement, FuSymbol, FuContainerType, FuEnum, FuClass, FuMember, FuField, FuMethod } from "./fucheck.js";
import { FuParser, FuProgram, FuSystem, FuSema, FuSemaHost, FuSymbolReferenceVisitor, FuStatement, FuSymbol, FuContainerType,
FuEnum, FuClass, FuMember, FuConst, FuVar, FuParameters, FuField, FuCallType, FuMethod } from "./fucheck.js";

class VsCodeHost extends FuSemaHost
{
Expand Down Expand Up @@ -136,6 +137,63 @@ class VsCodeDiagnostics extends VsCodeHost
}
}

class VsCodeSymbolLocator extends VsCodeHost
{
protected async findSymbol(document: vscode.TextDocument, position: vscode.Position): Promise<FuSymbol | null>
{
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();
}

static #getSignature(method: FuMethod): string
{
var code = method.callType == FuCallType.NORMAL ? "" : FuMethod.callTypeToString(method.callType) + " ";
code = `${code}${method.type} ${method.name}`;
if (!method.isStatic() && method.isMutator())
code += "!";
code += "(";
for (var param = method.firstParameter(); param != null;) {
code = `${code}${param.type} ${param.name}`;
param = param.nextVar();
if (param == null)
break;
code += ", ";
}
return code + ")";
}

async getHover(document: vscode.TextDocument, position: vscode.Position): Promise<vscode.Hover | null>
{
const symbol = await this.findSymbol(document, position);
if (symbol == null)
return null;
var code = symbol.name;
if (symbol instanceof FuClass)
code = `class ${code}`;
else if (symbol instanceof FuEnum)
code = `enum ${code}`;
else if (symbol instanceof FuConst)
code = `const ${symbol.type} ${code}`;
else if (symbol instanceof FuVar)
code = `(${symbol.parent instanceof FuParameters ? "parameter" : "local variable"}) ${symbol.type} ${code}`;
else if (symbol instanceof FuMethod)
code = VsCodeSymbolLocator.#getSignature(symbol);
else if (symbol instanceof FuField)
code = `(field) ${symbol.type} ${code}`;
else if (symbol instanceof FuMember) // property
code = `${symbol.type} ${code}`;
return new vscode.Hover(new vscode.MarkdownString().appendCodeblock(code, "fusion"));
}
}

class VsCodeReferenceCollector extends FuSymbolReferenceVisitor
{
provider: VsCodeGotoProvider;
Expand All @@ -152,24 +210,10 @@ class VsCodeReferenceCollector extends FuSymbolReferenceVisitor
}
}

class VsCodeGotoProvider extends VsCodeHost
class VsCodeGotoProvider extends VsCodeSymbolLocator
{
#locations: vscode.Location[] = [];

async #findSymbol(document: vscode.TextDocument, position: vscode.Position): Promise<FuSymbol | null>
{
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();
}

pushLocation(statement: FuStatement): void
{
if (statement.loc > 0) {
Expand All @@ -181,15 +225,15 @@ class VsCodeGotoProvider extends VsCodeHost

async findDefinition(document: vscode.TextDocument, position: vscode.Position): Promise<vscode.Location[]>
{
const symbol = await this.#findSymbol(document, position);
const symbol = await this.findSymbol(document, position);
if (symbol != null)
this.pushLocation(symbol);
return this.#locations;
}

async findImplementations(document: vscode.TextDocument, position: vscode.Position): Promise<vscode.Location[]>
{
const symbol = await this.#findSymbol(document, position);
const symbol = await this.findSymbol(document, position);
if (symbol != null) {
if (symbol instanceof FuClass) {
for (const subclass of this.program.classes) {
Expand All @@ -211,7 +255,7 @@ class VsCodeGotoProvider extends VsCodeHost

async findReferences(document: vscode.TextDocument, position: vscode.Position): Promise<vscode.Location[]>
{
const symbol = await this.#findSymbol(document, position);
const symbol = await this.findSymbol(document, position);
if (symbol != null)
new VsCodeReferenceCollector(this).findReferences(this.program, symbol);
return this.#locations;
Expand Down Expand Up @@ -266,6 +310,11 @@ export function activate(context: vscode.ExtensionContext): void
}));
context.subscriptions.push(vscode.workspace.onDidChangeTextDocument(e => diagnostics.check(e.document)));
context.subscriptions.push(vscode.workspace.onDidCloseTextDocument(document => diagnostics.delete(document)));
vscode.languages.registerHoverProvider("fusion", {
provideHover(document, position, token) {
return new VsCodeSymbolLocator().getHover(document, position);
}
});
vscode.languages.registerDefinitionProvider("fusion", {
provideDefinition(document, position, token) {
return new VsCodeGotoProvider().findDefinition(document, position);
Expand Down
9 changes: 7 additions & 2 deletions editors/vscode/syntaxes/fusion.tmLanguage.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@
"include": "#comment"
},
{
"name": "storage.modifier.fu",
"match": "\\bpublic\\b"
"include": "#storage-modifier"
},
{
"include": "#enum-declaration"
Expand All @@ -23,6 +22,12 @@
},
{
"include": "#native-statement"
},
{
"include": "#type"
},
{
"include": "#method-declaration"
}
],
"repository": {
Expand Down
38 changes: 19 additions & 19 deletions libfut.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2352,6 +2352,24 @@ bool FuMethod::isAbstractVirtualOrOverride() const
return this->callType == FuCallType::abstract || this->callType == FuCallType::virtual_ || this->callType == FuCallType::override_;
}

std::string_view FuMethod::callTypeToString(FuCallType callType)
{
switch (callType) {
case FuCallType::static_:
return "static";
case FuCallType::abstract:
return "abstract";
case FuCallType::virtual_:
return "virtual";
case FuCallType::override_:
return "override";
case FuCallType::sealed:
return "sealed";
default:
std::abort();
}
}

FuVar * FuMethod::firstParameter() const
{
FuVar * first = static_cast<FuVar *>(this->parameters.first);
Expand Down Expand Up @@ -4214,32 +4232,14 @@ void FuParser::parseMethod(FuClass * klass, std::shared_ptr<FuMethod> method)
method->body = parseBlock(method.get());
}

std::string_view FuParser::callTypeToString(FuCallType callType)
{
switch (callType) {
case FuCallType::static_:
return "static";
case FuCallType::abstract:
return "abstract";
case FuCallType::virtual_:
return "virtual";
case FuCallType::override_:
return "override";
case FuCallType::sealed:
return "sealed";
default:
std::abort();
}
}

void FuParser::reportFormerError(int line, int column, int length, std::string_view message) const
{
this->host->reportError(this->host->program->sourceFiles.back().filename, line, column, column + length, message);
}

void FuParser::reportCallTypeError(int line, int column, std::string_view kind, FuCallType callType) const
{
std::string_view callTypeString = callTypeToString(callType);
std::string_view callTypeString = FuMethod::callTypeToString(callType);
reportFormerError(line, column, std::ssize(callTypeString), std::format("{} cannot be {}", kind, callTypeString));
}

Expand Down
38 changes: 19 additions & 19 deletions libfut.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2873,6 +2873,24 @@ public static FuMethod New(FuClass klass, FuVisibility visibility, FuCallType ca

public bool IsAbstractVirtualOrOverride() => this.CallType == FuCallType.Abstract || this.CallType == FuCallType.Virtual || this.CallType == FuCallType.Override;

public static string CallTypeToString(FuCallType callType)
{
switch (callType) {
case FuCallType.Static:
return "static";
case FuCallType.Abstract:
return "abstract";
case FuCallType.Virtual:
return "virtual";
case FuCallType.Override:
return "override";
case FuCallType.Sealed:
return "sealed";
default:
throw new NotImplementedException();
}
}

public FuVar FirstParameter()
{
FuVar first = (FuVar) this.Parameters.First;
Expand Down Expand Up @@ -4499,32 +4517,14 @@ void ParseMethod(FuClass klass, FuMethod method)
method.Body = ParseBlock(method);
}

static string CallTypeToString(FuCallType callType)
{
switch (callType) {
case FuCallType.Static:
return "static";
case FuCallType.Abstract:
return "abstract";
case FuCallType.Virtual:
return "virtual";
case FuCallType.Override:
return "override";
case FuCallType.Sealed:
return "sealed";
default:
throw new NotImplementedException();
}
}

void ReportFormerError(int line, int column, int length, string message)
{
this.Host.ReportError(this.Host.Program.SourceFiles[^1].Filename, line, column, column + length, message);
}

void ReportCallTypeError(int line, int column, string kind, FuCallType callType)
{
string callTypeString = CallTypeToString(callType);
string callTypeString = FuMethod.CallTypeToString(callType);
ReportFormerError(line, column, callTypeString.Length, $"{kind} cannot be {callTypeString}");
}

Expand Down
2 changes: 1 addition & 1 deletion libfut.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1343,6 +1343,7 @@ class FuMethod : public FuMethodBase
bool isStatic() const override;
bool isAbstractOrVirtual() const;
bool isAbstractVirtualOrOverride() const;
static std::string_view callTypeToString(FuCallType callType);
FuVar * firstParameter() const;
int getParametersCount() const;
const FuMethod * getDeclaringMethod() const;
Expand Down Expand Up @@ -1659,7 +1660,6 @@ class FuParser : public FuLexer
std::shared_ptr<FuStatement> parseStatement();
FuCallType parseCallType();
void parseMethod(FuClass * klass, std::shared_ptr<FuMethod> method);
static std::string_view callTypeToString(FuCallType callType);
void reportFormerError(int line, int column, int length, std::string_view message) const;
void reportCallTypeError(int line, int column, std::string_view kind, FuCallType callType) const;
void parseClass(std::shared_ptr<FuCodeDoc> doc, int line, int column, bool isPublic, FuCallType callType);
Expand Down
Loading

0 comments on commit ffc946d

Please sign in to comment.