Skip to content

Commit

Permalink
[vscode] Symbols: class, enum.
Browse files Browse the repository at this point in the history
  • Loading branch information
pfusik committed Apr 3, 2024
1 parent 265d74f commit 667acbf
Show file tree
Hide file tree
Showing 7 changed files with 159 additions and 38 deletions.
4 changes: 4 additions & 0 deletions AST.fu
Original file line number Diff line number Diff line change
Expand Up @@ -1277,6 +1277,10 @@ class FuMethodGroup : FuMember
public abstract class FuContainerType : FuType
{
internal bool IsPublic;
internal int StartLine;
internal int StartColumn;
internal int EndLine;
internal int EndColumn;
}

public class FuEnum : FuContainerType
Expand Down
33 changes: 24 additions & 9 deletions Parser.fu
Original file line number Diff line number Diff line change
Expand Up @@ -930,6 +930,17 @@ public class FuParser : FuLexer
method.Body = ParseBlock();
}

int GetCurrentLine() => this.Host.Program.LineLocs.Count - this.Host.Program.SourceFiles.Last().Line - 1;

int GetTokenColumn() => this.TokenLoc - this.Host.Program.LineLocs.Last();

void CloseContainer!(FuContainerType! type)
{
type.EndLine = GetCurrentLine();
type.EndColumn = this.Loc - this.Host.Program.LineLocs.Last();
Expect(FuToken.RightBrace);
}

static string CallTypeToString(FuCallType callType)
{
switch (callType) {
Expand All @@ -943,10 +954,10 @@ public class FuParser : FuLexer
}
}

void ParseClass!(FuCodeDoc# doc, bool isPublic, 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, IsPublic = isPublic, CallType = callType, Name = this.StringValue };
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)) {
Expand Down Expand Up @@ -1054,16 +1065,18 @@ public class FuParser : FuLexer
AddSymbol(klass, field);
Expect(FuToken.Semicolon);
}
Expect(FuToken.RightBrace);
CloseContainer(klass);
}

void ParseEnum!(FuCodeDoc# doc, bool isPublic)
void ParseEnum!(FuCodeDoc# doc, int line, int column, bool isPublic)
{
Expect(FuToken.Enum);
bool flags = Eat(FuToken.Asterisk);
FuEnum# enu = this.Host.Program.System.NewEnum(flags);
enu.Loc = this.TokenLoc;
enu.Documentation = doc;
enu.StartLine = line;
enu.StartColumn = column;
enu.Loc = this.TokenLoc;
enu.IsPublic = isPublic;
enu.Name = this.StringValue;
if (Expect(FuToken.Id))
Expand All @@ -1078,29 +1091,31 @@ public class FuParser : FuLexer
ReportError("enum* symbol must be assigned a value");
AddSymbol(enu, konst);
} while (Eat(FuToken.Comma));
Expect(FuToken.RightBrace);
CloseContainer(enu);
}

public void Parse!(string filename, byte[] input, int inputLength)
{
Open(filename, input, inputLength);
while (!See(FuToken.EndOfFile)) {
FuCodeDoc# doc = ParseDoc();
int line = GetCurrentLine();
int column = GetTokenColumn();
bool isPublic = Eat(FuToken.Public);
switch (this.CurrentToken) {
// class
case FuToken.Class:
ParseClass(doc, isPublic, FuCallType.Normal);
ParseClass(doc, line, column, isPublic, FuCallType.Normal);
break;
case FuToken.Static:
case FuToken.Abstract:
case FuToken.Sealed:
ParseClass(doc, isPublic, ParseCallType());
ParseClass(doc, line, column, isPublic, ParseCallType());
break;

// enum
case FuToken.Enum:
ParseEnum(doc, isPublic);
ParseEnum(doc, line, column, isPublic);
break;

// native
Expand Down
26 changes: 25 additions & 1 deletion editors/vscode/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 } from "./fucheck.js";
import { FuParser, FuProgram, FuSystem, FuSema, FuSemaHost, FuEnum } from "./fucheck.js";

class VsCodeHost extends FuSemaHost
{
Expand Down Expand Up @@ -154,6 +154,25 @@ class VsCodeDefinitionProvider extends VsCodeHost
}
}

class VsCodeSymbolProvider extends VsCodeHost
{
provideSymbols(document: vscode.TextDocument): vscode.DocumentSymbol[]
{
this.parseDocument(document, this.createParser());
const symbols : vscode.DocumentSymbol[] = [];
for (let container = this.program.first; container != null; container = container.next) {
const loc = container.loc;
const line = this.program.getLine(loc);
const startColumn = loc - this.program.lineLocs[line];
const endColumn = startColumn + container.getLocLength();
symbols.push(new vscode.DocumentSymbol(container.name, "", container instanceof FuEnum ? vscode.SymbolKind.Enum : vscode.SymbolKind.Class,
new vscode.Range(container.startLine, container.startColumn, container.endLine, container.endColumn),
new vscode.Range(line, startColumn, line, endColumn)));
}
return symbols;
}
}

export function activate(context: vscode.ExtensionContext): void
{
const diagnostics = new VsCodeDiagnostics();
Expand All @@ -170,4 +189,9 @@ export function activate(context: vscode.ExtensionContext): void
return new VsCodeDefinitionProvider().findDefinition(document, position);
}
});
vscode.languages.registerDocumentSymbolProvider("fusion", {
provideDocumentSymbols(document, token) {
return new VsCodeSymbolProvider().provideSymbols(document);
}
});
}
39 changes: 31 additions & 8 deletions libfut.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4106,6 +4106,23 @@ void FuParser::parseMethod(FuClass * klass, std::shared_ptr<FuMethod> method)
method->body = parseBlock();
}

int FuParser::getCurrentLine() const
{
return std::ssize(this->host->program->lineLocs) - this->host->program->sourceFiles.back().line - 1;
}

int FuParser::getTokenColumn() const
{
return this->tokenLoc - this->host->program->lineLocs.back();
}

void FuParser::closeContainer(FuContainerType * type)
{
type->endLine = getCurrentLine();
type->endColumn = this->loc - this->host->program->lineLocs.back();
expect(FuToken::rightBrace);
}

std::string_view FuParser::callTypeToString(FuCallType callType)
{
switch (callType) {
Expand All @@ -4126,12 +4143,14 @@ std::string_view FuParser::callTypeToString(FuCallType callType)
}
}

void FuParser::parseClass(std::shared_ptr<FuCodeDoc> doc, bool isPublic, FuCallType callType)
void FuParser::parseClass(std::shared_ptr<FuCodeDoc> doc, int line, int column, bool isPublic, FuCallType callType)
{
expect(FuToken::class_);
std::shared_ptr<FuClass> klass = std::make_shared<FuClass>();
klass->loc = this->tokenLoc;
klass->documentation = doc;
klass->startLine = line;
klass->startColumn = column;
klass->isPublic = isPublic;
klass->callType = callType;
klass->name = this->stringValue;
Expand Down Expand Up @@ -4240,16 +4259,18 @@ void FuParser::parseClass(std::shared_ptr<FuCodeDoc> doc, bool isPublic, FuCallT
addSymbol(klass.get(), field);
expect(FuToken::semicolon);
}
expect(FuToken::rightBrace);
closeContainer(klass.get());
}

void FuParser::parseEnum(std::shared_ptr<FuCodeDoc> doc, bool isPublic)
void FuParser::parseEnum(std::shared_ptr<FuCodeDoc> doc, int line, int column, bool isPublic)
{
expect(FuToken::enum_);
bool flags = eat(FuToken::asterisk);
std::shared_ptr<FuEnum> enu = this->host->program->system->newEnum(flags);
enu->loc = this->tokenLoc;
enu->documentation = doc;
enu->startLine = line;
enu->startColumn = column;
enu->loc = this->tokenLoc;
enu->isPublic = isPublic;
enu->name = this->stringValue;
if (expect(FuToken::id))
Expand All @@ -4271,26 +4292,28 @@ void FuParser::parseEnum(std::shared_ptr<FuCodeDoc> doc, bool isPublic)
addSymbol(enu.get(), konst);
}
while (eat(FuToken::comma));
expect(FuToken::rightBrace);
closeContainer(enu.get());
}

void FuParser::parse(std::string_view filename, uint8_t const * input, int inputLength)
{
open(filename, input, inputLength);
while (!see(FuToken::endOfFile)) {
std::shared_ptr<FuCodeDoc> doc = parseDoc();
int line = getCurrentLine();
int column = getTokenColumn();
bool isPublic = eat(FuToken::public_);
switch (this->currentToken) {
case FuToken::class_:
parseClass(doc, isPublic, FuCallType::normal);
parseClass(doc, line, column, isPublic, FuCallType::normal);
break;
case FuToken::static_:
case FuToken::abstract:
case FuToken::sealed:
parseClass(doc, isPublic, parseCallType());
parseClass(doc, line, column, isPublic, parseCallType());
break;
case FuToken::enum_:
parseEnum(doc, isPublic);
parseEnum(doc, line, column, isPublic);
break;
case FuToken::native:
this->host->program->topLevelNatives.push_back(parseNative()->content);
Expand Down
41 changes: 32 additions & 9 deletions libfut.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2839,6 +2839,14 @@ public abstract class FuContainerType : FuType
{

internal bool IsPublic;

internal int StartLine;

internal int StartColumn;

internal int EndLine;

internal int EndColumn;
}

public class FuEnum : FuContainerType
Expand Down Expand Up @@ -4382,6 +4390,17 @@ void ParseMethod(FuClass klass, FuMethod method)
method.Body = ParseBlock();
}

int GetCurrentLine() => this.Host.Program.LineLocs.Count - this.Host.Program.SourceFiles[^1].Line - 1;

int GetTokenColumn() => this.TokenLoc - this.Host.Program.LineLocs[^1];

void CloseContainer(FuContainerType type)
{
type.EndLine = GetCurrentLine();
type.EndColumn = this.Loc - this.Host.Program.LineLocs[^1];
Expect(FuToken.RightBrace);
}

static string CallTypeToString(FuCallType callType)
{
switch (callType) {
Expand All @@ -4402,10 +4421,10 @@ static string CallTypeToString(FuCallType callType)
}
}

void ParseClass(FuCodeDoc doc, bool isPublic, 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, IsPublic = isPublic, CallType = callType, Name = this.StringValue };
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)) {
Expand Down Expand Up @@ -4490,16 +4509,18 @@ void ParseClass(FuCodeDoc doc, bool isPublic, FuCallType callType)
AddSymbol(klass, field);
Expect(FuToken.Semicolon);
}
Expect(FuToken.RightBrace);
CloseContainer(klass);
}

void ParseEnum(FuCodeDoc doc, bool isPublic)
void ParseEnum(FuCodeDoc doc, int line, int column, bool isPublic)
{
Expect(FuToken.Enum);
bool flags = Eat(FuToken.Asterisk);
FuEnum enu = this.Host.Program.System.NewEnum(flags);
enu.Loc = this.TokenLoc;
enu.Documentation = doc;
enu.StartLine = line;
enu.StartColumn = column;
enu.Loc = this.TokenLoc;
enu.IsPublic = isPublic;
enu.Name = this.StringValue;
if (Expect(FuToken.Id))
Expand All @@ -4515,26 +4536,28 @@ void ParseEnum(FuCodeDoc doc, bool isPublic)
AddSymbol(enu, konst);
}
while (Eat(FuToken.Comma));
Expect(FuToken.RightBrace);
CloseContainer(enu);
}

public void Parse(string filename, byte[] input, int inputLength)
{
Open(filename, input, inputLength);
while (!See(FuToken.EndOfFile)) {
FuCodeDoc doc = ParseDoc();
int line = GetCurrentLine();
int column = GetTokenColumn();
bool isPublic = Eat(FuToken.Public);
switch (this.CurrentToken) {
case FuToken.Class:
ParseClass(doc, isPublic, FuCallType.Normal);
ParseClass(doc, line, column, isPublic, FuCallType.Normal);
break;
case FuToken.Static:
case FuToken.Abstract:
case FuToken.Sealed:
ParseClass(doc, isPublic, ParseCallType());
ParseClass(doc, line, column, isPublic, ParseCallType());
break;
case FuToken.Enum:
ParseEnum(doc, isPublic);
ParseEnum(doc, line, column, isPublic);
break;
case FuToken.Native:
this.Host.Program.TopLevelNatives.Add(ParseNative().Content);
Expand Down
11 changes: 9 additions & 2 deletions libfut.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1341,6 +1341,10 @@ class FuContainerType : public FuType
FuContainerType() = default;
public:
bool isPublic;
int startLine;
int startColumn;
int endLine;
int endColumn;
};

class FuEnum : public FuContainerType
Expand Down Expand Up @@ -1619,9 +1623,12 @@ class FuParser : public FuLexer
std::shared_ptr<FuStatement> parseStatement();
FuCallType parseCallType();
void parseMethod(FuClass * klass, std::shared_ptr<FuMethod> method);
int getCurrentLine() const;
int getTokenColumn() const;
void closeContainer(FuContainerType * type);
static std::string_view callTypeToString(FuCallType callType);
void parseClass(std::shared_ptr<FuCodeDoc> doc, bool isPublic, FuCallType callType);
void parseEnum(std::shared_ptr<FuCodeDoc> doc, bool isPublic);
void parseClass(std::shared_ptr<FuCodeDoc> doc, int line, int column, bool isPublic, FuCallType callType);
void parseEnum(std::shared_ptr<FuCodeDoc> doc, int line, int column, bool isPublic);
};

class FuSemaHost : public FuParserHost
Expand Down
Loading

0 comments on commit 667acbf

Please sign in to comment.