Skip to content

Commit

Permalink
[vscode] Symbols: members.
Browse files Browse the repository at this point in the history
  • Loading branch information
pfusik committed Apr 3, 2024
1 parent 667acbf commit c39a601
Show file tree
Hide file tree
Showing 8 changed files with 257 additions and 124 deletions.
4 changes: 4 additions & 0 deletions AST.fu
Original file line number Diff line number Diff line change
Expand Up @@ -1139,6 +1139,10 @@ public abstract class FuNamedValue : FuSymbol
public abstract class FuMember : FuNamedValue
{
internal FuVisibility Visibility;
internal int StartLine;
internal int StartColumn;
internal int EndLine;
internal int EndColumn;
protected FuMember()
{
}
Expand Down
76 changes: 50 additions & 26 deletions Parser.fu
Original file line number Diff line number Diff line change
Expand Up @@ -552,7 +552,7 @@ public class FuParser : FuLexer
NextToken();
Expect(FuToken.Assign);
konst.Value = ParseConstInitializer();
Expect(FuToken.Semicolon);
CloseMember(FuToken.Semicolon, konst);
return konst;
}

Expand Down Expand Up @@ -581,13 +581,13 @@ public class FuParser : FuLexer
}
}

FuBlock# ParseBlock!()
FuBlock# ParseBlock!(FuMethodBase!? method)
{
FuBlock# result = new FuBlock { Loc = this.TokenLoc };
Expect(FuToken.LeftBrace);
while (!See(FuToken.RightBrace) && !See(FuToken.EndOfFile))
result.Statements.Add(ParseStatement());
Expect(FuToken.RightBrace);
CloseMember(FuToken.RightBrace, method);
return result;
}

Expand Down Expand Up @@ -739,13 +739,37 @@ public class FuParser : FuLexer
return result;
}

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

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

void SetMemberEnd(FuMember! member)
{
member.EndLine = GetCurrentLine();
member.EndColumn = this.Loc - this.Host.Program.LineLocs.Last();
}

void CloseMember!(FuToken expected, FuMember!? member)
{
if (member != null)
SetMemberEnd(member);
Expect(expected);
}

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

FuReturn# ParseReturn!(FuMethod!? method)
{
FuReturn# result = new FuReturn { Loc = this.TokenLoc };
NextToken();
if (!See(FuToken.Semicolon))
result.Value = ParseExpr();
Expect(FuToken.Semicolon);
CloseMember(FuToken.Semicolon, method);
return result;
}

Expand Down Expand Up @@ -831,7 +855,7 @@ public class FuParser : FuLexer
{
switch (this.CurrentToken) {
case FuToken.LeftBrace:
return ParseBlock();
return ParseBlock(null);
case FuToken.Assert:
return ParseAssert();
case FuToken.Break:
Expand All @@ -853,7 +877,7 @@ public class FuParser : FuLexer
case FuToken.Native:
return ParseNative();
case FuToken.Return:
return ParseReturn();
return ParseReturn(null);
case FuToken.Switch:
return ParseSwitch();
case FuToken.Throw:
Expand Down Expand Up @@ -923,22 +947,11 @@ public class FuParser : FuLexer
} while (Eat(FuToken.Comma));
}
if (method.CallType == FuCallType.Abstract)
Expect(FuToken.Semicolon);
CloseMember(FuToken.Semicolon, method);
else if (See(FuToken.FatArrow))
method.Body = ParseReturn();
method.Body = ParseReturn(method);
else if (Check(FuToken.LeftBrace))
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);
method.Body = ParseBlock(method);
}

static string CallTypeToString(FuCallType callType)
Expand Down Expand Up @@ -969,6 +982,9 @@ public class FuParser : FuLexer
while (!See(FuToken.RightBrace) && !See(FuToken.EndOfFile)) {
doc = ParseDoc();

int line = GetCurrentLine();
int column = GetTokenColumn();

FuVisibility visibility;
switch (this.CurrentToken) {
case FuToken.Internal:
Expand All @@ -991,6 +1007,8 @@ public class FuParser : FuLexer
if (See(FuToken.Const)) {
// const
FuConst# konst = ParseConst(visibility);
konst.StartLine = line;
konst.StartColumn = column;
konst.Documentation = doc;
AddSymbol(klass, konst);
continue;
Expand All @@ -1014,10 +1032,11 @@ public class FuParser : FuLexer
}
if (visibility == FuVisibility.Private)
visibility = FuVisibility.Internal; // TODO
klass.Constructor = new FuMethodBase { Loc = call.Loc, Documentation = doc, Visibility = visibility, Parent = klass,
Type = this.Host.Program.System.VoidType, Name = klass.Name, Body = ParseBlock() };
klass.Constructor = new FuMethodBase { StartLine = line, StartColumn = column, Loc = call.Loc, Documentation = doc,
Visibility = visibility, Parent = klass, Type = this.Host.Program.System.VoidType, Name = klass.Name };
klass.Constructor.Parameters.Parent = klass;
klass.Constructor.AddThis(klass, true);
klass.Constructor.Body = ParseBlock(klass.Constructor);
continue;
}

Expand Down Expand Up @@ -1049,7 +1068,8 @@ public class FuParser : FuLexer
if (visibility == FuVisibility.Private && callType != FuCallType.Static && callType != FuCallType.Normal)
ReportError($"{CallTypeToString(callType)} method cannot be private");

FuMethod# method = new FuMethod { Loc = loc, Documentation = doc, Visibility = visibility, CallType = callType, TypeExpr = type, Name = name };
FuMethod# method = new FuMethod { StartLine = line, StartColumn = column, Loc = loc, Documentation = doc,
Visibility = visibility, CallType = callType, TypeExpr = type, Name = name };
ParseMethod(klass, method);
continue;
}
Expand All @@ -1061,9 +1081,10 @@ public class FuParser : FuLexer
ReportError($"Field cannot be {CallTypeToString(callType)}");
if (type == this.Host.Program.System.VoidType)
ReportError("Field cannot be void");
FuField# field = new FuField { Loc = loc, Documentation = doc, Visibility = visibility, TypeExpr = type, Name = name, Value = ParseInitializer() };
FuField# field = new FuField { StartLine = line, StartColumn = column, Loc = loc, Documentation = doc,
Visibility = visibility, TypeExpr = type, Name = name, Value = ParseInitializer() };
AddSymbol(klass, field);
Expect(FuToken.Semicolon);
CloseMember(FuToken.Semicolon, field);
}
CloseContainer(klass);
}
Expand All @@ -1084,12 +1105,15 @@ public class FuParser : FuLexer
Expect(FuToken.LeftBrace);
do {
FuConst# konst = new FuConst { Visibility = FuVisibility.Public, Documentation = ParseDoc(), Loc = this.TokenLoc, Name = this.StringValue, Type = enu, VisitStatus = FuVisitStatus.NotYet };
konst.StartLine = GetCurrentLine();
konst.StartColumn = GetTokenColumn();
Expect(FuToken.Id);
if (Eat(FuToken.Assign))
konst.Value = ParseExpr();
else if (flags)
ReportError("enum* symbol must be assigned a value");
AddSymbol(enu, konst);
SetMemberEnd(konst);
} while (Eat(FuToken.Comma));
CloseContainer(enu);
}
Expand Down
1 change: 1 addition & 0 deletions editors/vscode/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ A Visual Studio Code extension for the [Fusion programming language](https://fus

* Syntax highlighting
* Error highlighting
* Outline
* Go to definition
* Snippets

Expand Down
34 changes: 26 additions & 8 deletions 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, FuEnum } from "./fucheck.js";
import { FuParser, FuProgram, FuSystem, FuSema, FuSemaHost, FuContainerType, FuEnum, FuMember, FuField, FuMethod } from "./fucheck.js";

class VsCodeHost extends FuSemaHost
{
Expand Down Expand Up @@ -156,18 +156,36 @@ class VsCodeDefinitionProvider extends VsCodeHost

class VsCodeSymbolProvider extends VsCodeHost
{
#createSymbol(source: FuContainerType | FuMember, kind: vscode.SymbolKind): vscode.DocumentSymbol
{
const line = this.program.getLine(source.loc);
const column = source.loc - this.program.lineLocs[line];
return new vscode.DocumentSymbol(source.name, "", kind,
new vscode.Range(source.startLine, source.startColumn, source.endLine, source.endColumn),
new vscode.Range(line, column, line, column + source.getLocLength()));
}

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)));
if (container instanceof FuEnum) {
const containerSymbol = this.#createSymbol(container, vscode.SymbolKind.Enum);
for (let member: FuMember = container.getFirstValue(); member != null; member = member.next)
containerSymbol.children.push(this.#createSymbol(member, vscode.SymbolKind.EnumMember));
symbols.push(containerSymbol);
}
else {
const containerSymbol = this.#createSymbol(container, vscode.SymbolKind.Class);
if (container.constructor_ != null)
containerSymbol.children.push(this.#createSymbol(container.constructor_, vscode.SymbolKind.Constructor));
for (let member = container.first; member != null; member = member.next) {
containerSymbol.children.push(this.#createSymbol(member, member instanceof FuMethod ? vscode.SymbolKind.Method :
member instanceof FuField ? vscode.SymbolKind.Field : vscode.SymbolKind.Constant));
}
symbols.push(containerSymbol);
}
}
return symbols;
}
Expand Down
Loading

0 comments on commit c39a601

Please sign in to comment.