Skip to content

Commit

Permalink
WIP building symbol table.
Browse files Browse the repository at this point in the history
  • Loading branch information
pherrymason committed Dec 26, 2024
1 parent 5e68044 commit f4d31ab
Show file tree
Hide file tree
Showing 29 changed files with 4,539 additions and 4,350 deletions.
47 changes: 2 additions & 45 deletions server/internal/lsp/analysis/analysis.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,51 +8,6 @@ import (
"go/token"
)

// SymbolTable stores list of symbols defined in the project.
// Each symbol has an "address". This address allows to now where the symbol
/*
// Ideas:
// module.[global|scope(funName)].symbolName
// this would cover:
// module foo;
// int symbol;
// fn void foo(){ int symbol; }
// This does not cover:
// module foo;
// fn void foo(){
// int symbol; // #1
// {
// int symbol; // #2
// }
// {
// char symbol; // #3
// {
// float symbol; //#4
// }
// }
// }
//
// Ideas:
// #1: foo.foo.symbol <-- declared in root scope
// #2: foo.foo[1].symbol <-- First sub scope
// #3: foo.foo[2].symbol <-- Second sub scope
// #4: foo.foo[2][0].symbol <-- Second sub scope, First sub scope
//
// Idea 2. Not sure if this will allow to find them, but maybe this scope
// location would be useful to have to disambiguate, better storing it
// in a different column
symbol table
--------------
id: primary key
symbol_name: name of the symbol
module: module name where this is defined
path: full route to reach this symbol
scope_path: Example [2][0]. Helps determining what is the scope this is defined.
*/
type SymbolTable struct {
}

type Location struct {
Uri protocol.URI
Range protocol.Range
Expand Down Expand Up @@ -99,4 +54,6 @@ func FindNodeAtPosition(n ast.Node, fset *token.FileSet, pos lsp.Position) ast.N
(end.Line > pos.Line || (end.Line == pos.Line && end.Column >= pos.Column)) {

}

return n
}
133 changes: 133 additions & 0 deletions server/internal/lsp/analysis/symbol_table.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
package analysis

import (
"github.com/pherrymason/c3-lsp/internal/lsp"
"github.com/pherrymason/c3-lsp/internal/lsp/ast"
"github.com/pherrymason/c3-lsp/internal/lsp/ast/walk"
)

// SymbolTable stores list of symbols defined in the project.
// Each symbol has an "address". This address allows to now where the symbol
/*
// Ideas:
// module.[global|scope(funName)].symbolName
// this would cover:
// module foo;
// int symbol;
// fn void foo(){ int symbol; }
// This does not cover:
// module foo;
// fn void foo(){
// int symbol; // #1
// {
// int symbol; // #2
// }
// {
// char symbol; // #3
// {
// float symbol; //#4
// }
// }
// }
//
// Ideas:
// #1: foo.foo.symbol <-- declared in root scope
// #2: foo.foo[1].symbol <-- First sub scope
// #3: foo.foo[2].symbol <-- Second sub scope
// #4: foo.foo[2][0].symbol <-- Second sub scope, First sub scope
//
// Idea 2. Not sure if this will allow to find them, but maybe this scope
// location would be useful to have to disambiguate, better storing it
// in a different column
symbol table
--------------
id: primary key
symbol_name: name of the symbol
module: module name where this is defined
path: full route to reach this symbol
scope_path: Example [2][0]. Helps determining what is the scope this is defined.
*/
type SymbolTable struct {
// Each position inside symbols is the ID of the symbol which can be referenced in other index tables.
symbols []Symbol
}

func (s *SymbolTable) RegisterVariable(genDecl *ast.GenDecl, currentModule ast.Module) {
s.symbols = append(s.symbols, Symbol{
Name: genDecl.Spec.(*ast.ValueSpec).Names[0].Name,
Module: []string{currentModule.Name},
NodeDecl: genDecl,
Range: genDecl.Range,
})
}
func (s *SymbolTable) RegisterType(typeDecl *ast.GenDecl, currentModule ast.Module) {
s.symbols = append(s.symbols, Symbol{
Name: typeDecl.Spec.(*ast.TypeSpec).Name.Name,
Module: []string{currentModule.Name},
NodeDecl: typeDecl,
Range: typeDecl.Range,
})
}

type SymbolID uint

type Symbol struct {
Name string
Module ModuleName
Range lsp.Range
NodeDecl ast.Node // Declaration node of this symbol
Type TypeDefinition
}

type ModuleName []string

type TypeDefinition struct {
Name string
IsBuiltIn bool // Is it a built in type definition?
NodeDecl ast.Node
}

// ScopeTable represents the list of symbols declared in a scope
type ScopeTable struct {
Range lsp.Range
Symbols []SymbolID
}

func BuildSymbolTable(astTree ast.Node) SymbolTable {
visitor := symbolTableGenerator{}
walk.Walk(&visitor, astTree)

return visitor.table
}

type symbolTableGenerator struct {
table SymbolTable

// State properties to keep track
currentModule ast.Module
}

func (v *symbolTableGenerator) Enter(node ast.Node) walk.Visitor {
switch n := node.(type) {
case ast.Module:
v.currentModule = ast.Module{
Name: n.Name,
GenericParameters: n.GenericParameters,
NodeAttributes: n.NodeAttributes,
}

case *ast.GenDecl:
if n.Token == ast.VAR {
v.table.RegisterVariable(n, v.currentModule)
} else if n.Token == ast.ENUM || n.Token == ast.STRUCT {
v.table.RegisterType(n, v.currentModule)
}
}

return v
}

func (v *symbolTableGenerator) Exit(n ast.Node) {

}
27 changes: 27 additions & 0 deletions server/internal/lsp/analysis/symbol_table_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package analysis

import (
"github.com/pherrymason/c3-lsp/internal/lsp/ast/factory"
"github.com/stretchr/testify/assert"
"testing"
)

func TestConvertToAST_registers_global_declarations(t *testing.T) {
source := `
module foo;
int cat = 1;
char dog = 2;
enum Colors:int { RED, BLUE, GREEN }
struct MyStruct { int data; }
`

tree := factory.ConvertToAST(factory.GetCST(source), source, "file.c3")

result := BuildSymbolTable(tree)

assert.Equal(t, 4, len(result.symbols))
assert.Equal(t, "cat", result.symbols[0].Name)
assert.Equal(t, "dog", result.symbols[1].Name)
assert.Equal(t, "Colors", result.symbols[2].Name)
assert.Equal(t, "MyStruct", result.symbols[3].Name)
}
37 changes: 18 additions & 19 deletions server/internal/lsp/ast/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ const (
CHAR // 'a'
STRING
BOOLEAN

// Types
VAR
CONST
STRUCT
ENUM
FAULT
)

type Token int
Expand Down Expand Up @@ -67,24 +74,17 @@ func (n *EmptyNode) stmtNode() {}
// NodeAttributes is a struct that contains the common information all
// AST Nodes contains, like position or other attributes
type NodeAttributes struct {
StartPos, EndPos lsp.Position
Range lsp.Range
Parent Node
Attributes []string
Range lsp.Range
Attributes []string
}

func (n NodeAttributes) StartPosition() lsp.Position { return n.StartPos }
func (n NodeAttributes) EndPosition() lsp.Position { return n.EndPos }
func SetParent(parent Node, child *NodeAttributes) { child.Parent = parent }
func (n NodeAttributes) StartPosition() lsp.Position { return n.Range.Start }
func (n NodeAttributes) EndPosition() lsp.Position { return n.Range.End }

func ChangeNodePosition(n *NodeAttributes, start sitter.Point, end sitter.Point) {
n.StartPos = lsp.Position{Line: uint(start.Row), Column: uint(start.Column)}
n.EndPos = lsp.Position{Line: uint(end.Row), Column: uint(end.Column)}
} /*
func (n *NodeAttributes) SetPos(start sitter.Point, end sitter.Point) {
n.StartPos = Position{Line: uint(start.Row), Column: uint(start.Column)}
n.EndPos = Position{Line: uint(end.Row), Column: uint(end.Column)}
}*/
n.Range.Start = lsp.Position{Line: uint(start.Row), Column: uint(start.Column)}
n.Range.End = lsp.Position{Line: uint(end.Row), Column: uint(end.Column)}
}

type File struct {
NodeAttributes
Expand All @@ -100,11 +100,11 @@ func NewFile(name string, aRange lsp.Range, modules []Module) *File {
Modules: modules,
}

for i := range node.Modules {
SetParent(node, &node.Modules[i].NodeAttributes)
}
return node
}
func (f *File) AddModule(module Module) {
f.Modules = append(f.Modules, module)
}

type Module struct {
NodeAttributes
Expand All @@ -118,8 +118,7 @@ func NewModule(name string, aRange lsp.Range, file *File) *Module {
return &Module{
Name: name,
NodeAttributes: NodeAttributes{
Parent: file,
Range: aRange,
Range: aRange,
},
}
}
Expand Down
Loading

0 comments on commit f4d31ab

Please sign in to comment.