Skip to content

Commit

Permalink
Refactor: Use custom Range and Position in server package.
Browse files Browse the repository at this point in the history
Implement searching enum and enumerators.
Parse enums with base type (ignoring base type for now).
  • Loading branch information
pherrymason committed Jan 12, 2024
1 parent af9f482 commit 0c312c8
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 48 deletions.
2 changes: 1 addition & 1 deletion server/lsp/documentstore.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ func (s *documentStore) normalizePath(pathOrUri string) (string, error) {
return fs.GetCanonicalPath(path), nil
}

func (s *documentStore) DidOpen(params protocol.DidOpenTextDocumentParams, notify glsp.NotifyFunc) (*Document, error) {
func (s *documentStore) DidOpen(params protocol.DidOpenTextDocumentParams, notify glsp.NotifyFunc, parser *Parser) (*Document, error) {
langID := params.TextDocument.LanguageID
if langID != "c3" {
return nil, nil
Expand Down
4 changes: 2 additions & 2 deletions server/lsp/language.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ func NewLanguage() Language {
}
}

func (l *Language) RefreshDocumentIdentifiers(doc *Document) {
l.functionTreeByDocument[doc.URI] = FindSymbols(doc)
func (l *Language) RefreshDocumentIdentifiers(doc *Document, parser *Parser) {
l.functionTreeByDocument[doc.URI] = parser.FindSymbols(doc)
}

func (l *Language) BuildCompletionList(text string, line protocol.UInteger, character protocol.UInteger) []protocol.CompletionItem {
Expand Down
32 changes: 21 additions & 11 deletions server/lsp/language_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,22 @@ import (
"fmt"
"github.com/pherrymason/c3-lsp/lsp/indexables"
"github.com/stretchr/testify/assert"
"github.com/tliron/commonlog"
protocol "github.com/tliron/glsp/protocol_3_16"
"testing"
)

func TestLanguage_FindHoverInformation(t *testing.T) {
language := NewLanguage()
parser := createParser()

doc := NewDocumentFromString("x", `
int value = 1;
fn void main() {
char value = 3;
}
`)
language.RefreshDocumentIdentifiers(&doc)
language.RefreshDocumentIdentifiers(&doc, &parser)

params := protocol.HoverParams{
TextDocumentPositionParams: protocol.TextDocumentPositionParams{
Expand All @@ -43,18 +45,19 @@ func TestLanguage_FindHoverInformation(t *testing.T) {

func TestLanguage_FindHoverInformationFromDifferentFile(t *testing.T) {
language := NewLanguage()
parser := createParser()

doc := NewDocumentFromString("x", `
fn void main() {
importedMethod();
}
`)
language.RefreshDocumentIdentifiers(&doc)
language.RefreshDocumentIdentifiers(&doc, &parser)

doc2 := NewDocumentFromString("y", `
fn void importedMethod() {}
`)
language.RefreshDocumentIdentifiers(&doc2)
language.RefreshDocumentIdentifiers(&doc2, &parser)

params := protocol.HoverParams{
TextDocumentPositionParams: protocol.TextDocumentPositionParams{
Expand Down Expand Up @@ -156,7 +159,8 @@ func TestLanguage_FindSymbolDeclarationInWorkspace_symbol_same_scope(t *testing.
t.Run(tt.name, func(t *testing.T) {
doc := NewDocumentFromString("x", tt.sourceCode)
language := NewLanguage()
language.RefreshDocumentIdentifiers(&doc)
parser := createParser()
language.RefreshDocumentIdentifiers(&doc, &parser)

params := newDeclarationParams("x", tt.cursorPositionLine, tt.cursorPositionChar)

Expand All @@ -169,12 +173,12 @@ func TestLanguage_FindSymbolDeclarationInWorkspace_symbol_same_scope(t *testing.

func TestLanguage_FindSymbolDeclarationInWorkspace_variable_same_scope(t *testing.T) {
language := NewLanguage()

parser := createParser()
doc := NewDocumentFromString("x", `
int value = 1;
value = 3;
`)
language.RefreshDocumentIdentifiers(&doc)
language.RefreshDocumentIdentifiers(&doc, &parser)

params := protocol.DeclarationParams{
TextDocumentPositionParams: protocol.TextDocumentPositionParams{
Expand All @@ -199,14 +203,14 @@ func TestLanguage_FindSymbolDeclarationInWorkspace_variable_same_scope(t *testin

func TestLanguage_FindSymbolDeclarationInWorkspace_variable_outside_current_function(t *testing.T) {
language := NewLanguage()

parser := createParser()
doc := NewDocumentFromString("x", `
int value = 1;
fn void main() {
value = 3;
}
`)
language.RefreshDocumentIdentifiers(&doc)
language.RefreshDocumentIdentifiers(&doc, &parser)

params := protocol.DeclarationParams{
TextDocumentPositionParams: protocol.TextDocumentPositionParams{
Expand All @@ -231,15 +235,15 @@ func TestLanguage_FindSymbolDeclarationInWorkspace_variable_outside_current_func

func TestLanguage_FindSymbolDeclarationInWorkspace_variable_outside_current_file(t *testing.T) {
language := NewLanguage()

parser := createParser()
doc := NewDocumentFromString("x", `
fn void main() {
value = 3;
}
`)
language.RefreshDocumentIdentifiers(&doc)
language.RefreshDocumentIdentifiers(&doc, &parser)
doc2 := NewDocumentFromString("y", `int value = 1;`)
language.RefreshDocumentIdentifiers(&doc2)
language.RefreshDocumentIdentifiers(&doc2, &parser)

params := protocol.DeclarationParams{
TextDocumentPositionParams: protocol.TextDocumentPositionParams{
Expand All @@ -261,3 +265,9 @@ func TestLanguage_FindSymbolDeclarationInWorkspace_variable_outside_current_file
)
assert.Equal(t, expectedSymbol, symbol)
}

func createParser() Parser {
return Parser{
logger: commonlog.MockLogger{},
}
}
38 changes: 20 additions & 18 deletions server/lsp/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"fmt"
idx "github.com/pherrymason/c3-lsp/lsp/indexables"
sitter "github.com/smacker/go-tree-sitter"
"github.com/tliron/commonlog"
protocol "github.com/tliron/glsp/protocol_3_16"
"unsafe"
)
Expand All @@ -20,6 +21,10 @@ const FunctionDeclarationQuery = `(function_declaration
)`
const EnumDeclaration = `(enum_declaration) @enum_dec`

type Parser struct {
logger commonlog.Logger
}

func getParser() *sitter.Parser {
parser := sitter.NewParser()
parser.SetLanguage(getLanguage())
Expand Down Expand Up @@ -47,7 +52,7 @@ func GetParsedTreeFromString(source string) *sitter.Tree {
return n
}

func FindSymbols(doc *Document) idx.Function {
func (p *Parser) FindSymbols(doc *Document) idx.Function {
query := `[
(source_file ` + VarDeclarationQuery + `)
(source_file ` + EnumDeclaration + `)
Expand Down Expand Up @@ -85,7 +90,7 @@ func FindSymbols(doc *Document) idx.Function {
if nodeType == "identifier" {
switch c.Node.Parent().Type() {
case "var_declaration":
variable := nodeToVariable(doc, c.Node, sourceCode, content)
variable := p.nodeToVariable(doc, c.Node, sourceCode, content)
scopeTree.AddVariables([]idx.Variable{
variable,
})
Expand All @@ -100,10 +105,10 @@ func FindSymbols(doc *Document) idx.Function {
scopeTree.AddFunction(&identifier)
}
} else if c.Node.Type() == "enum_declaration" {
enum := nodeToEnum(doc, c.Node, sourceCode)
enum := p.nodeToEnum(doc, c.Node, sourceCode)
scopeTree.AddEnum(&enum)
} else if nodeType == "compound_statement" {
variables := FindVariableDeclarations(doc, c.Node)
variables := p.FindVariableDeclarations(doc, c.Node)

// TODO Previous node has the info about which function is belongs to.
idNode := c.Node.Parent().ChildByFieldName("name")
Expand All @@ -123,7 +128,7 @@ func FindSymbols(doc *Document) idx.Function {
return scopeTree
}

func nodeToVariable(doc *Document, node *sitter.Node, sourceCode []byte, content string) idx.Variable {
func (p *Parser) nodeToVariable(doc *Document, node *sitter.Node, sourceCode []byte, content string) idx.Variable {
typeNode := node.PrevSibling()
typeNodeContent := typeNode.Content(sourceCode)
variable := idx.NewVariable(
Expand All @@ -138,21 +143,17 @@ func nodeToVariable(doc *Document, node *sitter.Node, sourceCode []byte, content
return variable
}

func nodeToEnum(doc *Document, node *sitter.Node, sourceCode []byte) idx.Enum {
func (p *Parser) nodeToEnum(doc *Document, node *sitter.Node, sourceCode []byte) idx.Enum {
nodesCount := node.ChildCount()
nameNode := node.Child(1)

baseType := ""
bodyIndex := 3
if nodesCount == 4 {
// Enum without base_type
} else {
// Enum with base_type
baseType = "?"
bodyIndex = 4
}
bodyIndex := int(nodesCount - 1)

// p.logger.Debug(fmt.Sprint(node.Content(sourceCode), ": Child count:", nodesCount))

enumeratorsNode := node.Child(bodyIndex)

enumerators := []idx.Enumerator{}
for i := uint32(0); i < enumeratorsNode.ChildCount(); i++ {
enumeratorNode := enumeratorsNode.Child(int(i))
Expand Down Expand Up @@ -180,6 +181,7 @@ func nodeToEnum(doc *Document, node *sitter.Node, sourceCode []byte) idx.Enum {
return enum
}

/**
func FindIdentifiers(doc *Document) []idx.Indexable {
//variableIdentifiers := FindVariableDeclarations(doc, doc.parsedTree.RootNode())
functionIdentifiers := FindFunctionDeclarations(doc)
Expand All @@ -189,9 +191,9 @@ func FindIdentifiers(doc *Document) []idx.Indexable {
elements = append(elements, functionIdentifiers...)
return elements
}
}*/

func FindVariableDeclarations(doc *Document, node *sitter.Node) []idx.Variable {
func (p *Parser) FindVariableDeclarations(doc *Document, node *sitter.Node) []idx.Variable {
query := VarDeclarationQuery
q, err := sitter.NewQuery([]byte(query), getLanguage())
if err != nil {
Expand All @@ -216,7 +218,7 @@ func FindVariableDeclarations(doc *Document, node *sitter.Node) []idx.Variable {

if _, exists := found[content]; !exists {
found[content] = true
variable := nodeToVariable(doc, c.Node, sourceCode, content)
variable := p.nodeToVariable(doc, c.Node, sourceCode, content)
identifiers = append(identifiers, variable)
}
}
Expand All @@ -225,7 +227,7 @@ func FindVariableDeclarations(doc *Document, node *sitter.Node) []idx.Variable {
return identifiers
}

func FindFunctionDeclarations(doc *Document) []idx.Indexable {
func (p *Parser) FindFunctionDeclarations(doc *Document) []idx.Indexable {
query := FunctionDeclarationQuery //`(function_declaration name: (identifier) @function_name)`
q, err := sitter.NewQuery([]byte(query), getLanguage())
if err != nil {
Expand Down
49 changes: 40 additions & 9 deletions server/lsp/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,9 @@ func TestFindIdentifiers_should_assign_different_scopes_to_same_name_identifiers
func TestFindSymbols_finds_function_root_and_global_variables_declarations(t *testing.T) {
source := `int value = 1;`
doc := NewDocumentFromString("x", source)
parser := createParser()

symbols := FindSymbols(&doc)
symbols := parser.FindSymbols(&doc)

expectedRoot := idx.NewAnonymousScopeFunction(
"main",
Expand All @@ -109,10 +110,11 @@ func TestFindSymbols_finds_function_root_and_global_variables_declarations(t *te
}

func TestFindSymbols_finds_function_root_and_global_enum_declarations(t *testing.T) {
source := `enum Colors = { RED, BLUE, GREEN };`
source := `enum Colors { RED, BLUE, GREEN };`
doc := NewDocumentFromString("x", source)
parser := createParser()

symbols := FindSymbols(&doc)
symbols := parser.FindSymbols(&doc)

expectedRoot := idx.NewAnonymousScopeFunction(
"main",
Expand All @@ -124,12 +126,41 @@ func TestFindSymbols_finds_function_root_and_global_enum_declarations(t *testing
"Colors",
"",
[]idx.Enumerator{
idx.NewEnumerator("RED", "", idx.NewRange(0, 16, 0, 19)),
idx.NewEnumerator("BLUE", "", idx.NewRange(0, 21, 0, 25)),
idx.NewEnumerator("GREEN", "", idx.NewRange(0, 27, 0, 32)),
idx.NewEnumerator("RED", "", idx.NewRange(0, 14, 0, 17)),
idx.NewEnumerator("BLUE", "", idx.NewRange(0, 19, 0, 23)),
idx.NewEnumerator("GREEN", "", idx.NewRange(0, 25, 0, 30)),
},
idx.NewRange(0, 5, 0, 11),
idx.NewRange(0, 0, 0, 34),
idx.NewRange(0, 0, 0, 32),
"x",
)
expectedRoot.AddEnum(&enum)
assert.Equal(t, &enum, symbols.Enums["Colors"])
}

func TestFindSymbols_finds_function_root_and_global_enum_with_base_type_declarations(t *testing.T) {
source := `enum Colors:int { RED, BLUE, GREEN };`
doc := NewDocumentFromString("x", source)
parser := createParser()

symbols := parser.FindSymbols(&doc)

expectedRoot := idx.NewAnonymousScopeFunction(
"main",
"x",
idx.NewRange(0, 0, 0, 35),
protocol.CompletionItemKindModule,
)
enum := idx.NewEnum(
"Colors",
"",
[]idx.Enumerator{
idx.NewEnumerator("RED", "", idx.NewRange(0, 18, 0, 21)),
idx.NewEnumerator("BLUE", "", idx.NewRange(0, 23, 0, 27)),
idx.NewEnumerator("GREEN", "", idx.NewRange(0, 29, 0, 34)),
},
idx.NewRange(0, 5, 0, 11),
idx.NewRange(0, 0, 0, 36),
"x",
)
expectedRoot.AddEnum(&enum)
Expand All @@ -145,8 +176,8 @@ func TestFindSymbols_finds_function_declaration_identifiers(t *testing.T) {
}
`
doc := NewDocumentFromString("x", source)

tree := FindSymbols(&doc)
parser := createParser()
tree := parser.FindSymbols(&doc)

function1 := idx.NewFunction("test", "x",
idx.NewRange(0, 8, 0, 12),
Expand Down
Loading

0 comments on commit 0c312c8

Please sign in to comment.