Skip to content

Commit

Permalink
ALL: Add interfaces
Browse files Browse the repository at this point in the history
  • Loading branch information
MineGame159 committed Jan 26, 2024
1 parent 122a7be commit d6a0b60
Show file tree
Hide file tree
Showing 41 changed files with 1,021 additions and 136 deletions.
7 changes: 7 additions & 0 deletions cmd/lsp/completion.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,10 @@ func getMemberCompletions(resolver ast.Resolver, c *completions, member *ast.Mem
for _, case_ := range e.Cases {
c.addNode(protocol.CompletionItemKindEnumMember, case_.Name, strconv.FormatInt(case_.ActualValue, 10))
}
} else if i, ok := asThroughPointer[*ast.Interface](member.Value.Result().Type); ok && member.Value.Result().Kind == ast.ValueResultKind {
for _, method := range i.Methods {
c.addNode(protocol.CompletionItemKindMethod, method.Name, printType(method))
}
}
}
}
Expand Down Expand Up @@ -341,6 +345,9 @@ func (c *completions) VisitSymbol(node ast.Node) {
case *ast.Enum:
c.addNode(protocol.CompletionItemKindEnum, node.Name, "")

case *ast.Interface:
c.addNode(protocol.CompletionItemKindInterface, node.Name, "")

case *ast.Func:
if !c.symbolsOnlyTypes {
c.addNode(protocol.CompletionItemKindFunction, node.Name, printType(node))
Expand Down
23 changes: 23 additions & 0 deletions cmd/lsp/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ func (h *handler) Initialize(_ context.Context, params *protocol.InitializeParam
protocol.SemanticTokenProperty,
protocol.SemanticTokenEnumMember,
protocol.SemanticTokenNamespace,
protocol.SemanticTokenInterface,
},
TokenModifiers: []protocol.SemanticTokenModifiers{},
},
Expand All @@ -114,6 +115,7 @@ func (h *handler) Initialize(_ context.Context, params *protocol.InitializeParam
InlayHintProvider: true,
WorkspaceSymbolProvider: true,
DefinitionProvider: true,
ImplementationProvider: true,
CompletionProvider: &protocol.CompletionOptions{
ResolveProvider: false,
TriggerCharacters: []string{" ", ".", ":", "=", "*", "&", ">", "<", "!"},
Expand Down Expand Up @@ -466,6 +468,27 @@ func (h *handler) Definition(_ context.Context, params *protocol.DefinitionParam
return getDefinition(file.Ast, pos), nil
}

func (h *handler) Implementation(_ context.Context, params *protocol.ImplementationParams) (result []protocol.Location, err error) {
defer stop(start(h, "Implementation"))

// Get document
file := h.getFile(params.TextDocument.URI)
if file == nil {
return nil, nil
}

file.EnsureChecked()

// Get position
pos := core.Pos{
Line: uint16(params.Position.Line + 1),
Column: uint16(params.Position.Character),
}

// Get declaration
return getImplementations(file.Ast, pos, file.Project.GetResolverRoot()), nil
}

func (h *handler) Completion(_ context.Context, params *protocol.CompletionParams) (result *protocol.CompletionList, err error) {
defer stop(start(h, "Completion"))

Expand Down
60 changes: 18 additions & 42 deletions cmd/lsp/highlighter.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,16 @@ package lsp
import (
"cmp"
"fireball/core/ast"
"fireball/core/scanner"
"fireball/core/utils"
"slices"
)

type highlighter struct {
enums utils.Set[string]

functions utils.Set[string]
params []*ast.Param

tokens []semantic
}

func highlight(node ast.Node) []uint32 {
h := highlighter{
enums: utils.NewSet[string](),
functions: utils.NewSet[string](),
tokens: make([]semantic, 0, 256),
}

for _, decl := range node.(*ast.File).Decls {
if v, ok := decl.(*ast.Enum); ok {
if v.Name != nil {
h.enums.Add(v.Name.String())
}
} else if v, ok := decl.(*ast.Func); ok {
if v.Name != nil {
h.functions.Add(v.Name.String())
}
}
tokens: make([]semantic, 0, 256),
}

h.VisitNode(node)
Expand Down Expand Up @@ -69,12 +48,6 @@ func (h *highlighter) VisitStruct(decl *ast.Struct) {
decl.AcceptChildren(h)
}

func (h *highlighter) VisitImpl(decl *ast.Impl) {
h.add(decl.Struct, classKind)

decl.AcceptChildren(h)
}

func (h *highlighter) VisitEnum(decl *ast.Enum) {
h.add(decl.Name, enumKind)

Expand All @@ -85,6 +58,18 @@ func (h *highlighter) VisitEnum(decl *ast.Enum) {
decl.AcceptChildren(h)
}

func (h *highlighter) VisitImpl(decl *ast.Impl) {
h.add(decl.Struct, classKind)

decl.AcceptChildren(h)
}

func (h *highlighter) VisitInterface(decl *ast.Interface) {
h.add(decl.Name, interfaceKind)

decl.AcceptChildren(h)
}

func (h *highlighter) VisitFunc(decl *ast.Func) {
if decl.Name != nil {
h.add(decl.Name, functionKind)
Expand All @@ -94,9 +79,7 @@ func (h *highlighter) VisitFunc(decl *ast.Func) {
h.add(param.Name, parameterKind)
}

h.params = decl.Params
decl.AcceptChildren(h)
h.params = nil
}

func (h *highlighter) VisitGlobalVar(decl *ast.GlobalVar) {
Expand Down Expand Up @@ -230,6 +213,8 @@ func (h *highlighter) visitExprResult(node ast.Node, result *ast.ExprResult) {
h.add(node, classKind)
case *ast.Enum:
h.add(node, enumKind)
case *ast.Interface:
h.add(node, interfaceKind)
}

case ast.ResolverResultKind:
Expand Down Expand Up @@ -270,6 +255,8 @@ func (h *highlighter) visitType(type_ ast.Type) {
h.add(type_.Parts[len(type_.Parts)-1], classKind)
case *ast.Enum:
h.add(type_.Parts[len(type_.Parts)-1], enumKind)
case *ast.Interface:
h.add(type_.Parts[len(type_.Parts)-1], interfaceKind)
}
}
}
Expand Down Expand Up @@ -310,6 +297,7 @@ const (
propertyKind
enumMemberKind
namespaceKind
interfaceKind
)

type semantic struct {
Expand Down Expand Up @@ -375,15 +363,3 @@ func (h *highlighter) data() []uint32 {

return data
}

// Utils

func (h *highlighter) isParameter(name scanner.Token) bool {
for _, param := range h.params {
if param.Name.String() == name.Lexeme {
return true
}
}

return false
}
55 changes: 55 additions & 0 deletions cmd/lsp/implementations.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package lsp

import (
"fireball/core"
"fireball/core/ast"
"github.com/MineGame159/protocol"
"go.lsp.dev/uri"
)

func getImplementations(node ast.Node, pos core.Pos, resolver ast.Resolver) []protocol.Location {
leaf := ast.GetLeaf(node, pos)

builder := implementationBuilder{}

switch parent := leaf.Parent().(type) {
case *ast.Interface:
builder.target = parent
builder.visit(resolver)

case *ast.Resolvable:
if inter, ok := ast.As[*ast.Interface](parent); ok {
builder.target = inter
builder.visit(resolver)
}
}

return builder.locations
}

type implementationBuilder struct {
target *ast.Interface
locations []protocol.Location
}

func (i *implementationBuilder) visit(resolver ast.Resolver) {
resolver.GetSymbols(i)

for _, child := range resolver.GetChildren() {
i.visit(resolver.GetChild(child))
}
}

func (i *implementationBuilder) VisitSymbol(node ast.Node) {
if impl, ok := node.(*ast.Impl); ok && i.target.Equals(impl.Implements) {
file := ast.GetParent[*ast.File](node)
if file == nil {
return
}

i.locations = append(i.locations, protocol.Location{
URI: uri.New(file.Path),
Range: convertRange(impl.Struct.Cst().Range),
})
}
}
30 changes: 29 additions & 1 deletion cmd/lsp/symbols.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,11 +130,11 @@ func getSymbols(symbols symbolConsumer, files []*workspace.File) {
} else if enum, ok := decl.(*ast.Enum); ok && nodeCst(enum) != nil && nodeCst(enum.Name) != nil {
// Enum
id := symbols.add(symbol{
file: file,
kind: protocol.SymbolKindEnum,
name: enum.Name.String(),
range_: nodeCst(enum).Range,
selectionRange: nodeCst(enum.Name).Range,
file: file,
}, len(enum.Cases))

for _, case_ := range enum.Cases {
Expand All @@ -149,6 +149,34 @@ func getSymbols(symbols symbolConsumer, files []*workspace.File) {
})
}
}
} else if inter, ok := decl.(*ast.Interface); ok && nodeCst(inter) != nil && nodeCst(inter.Name) != nil {
// Interface
id := symbols.add(symbol{
file: file,
kind: protocol.SymbolKindInterface,
name: inter.Name.String(),
range_: nodeCst(inter).Range,
selectionRange: nodeCst(inter.Name).Range,
}, len(inter.Methods))

for _, method := range inter.Methods {
if nodeCst(method.Name) != nil {
detail := ""

if symbols.supportsDetail() {
detail = method.Signature(true)
}

symbols.addChild(id, symbol{
file: file,
kind: protocol.SymbolKindMethod,
name: method.Name.String(),
detail: detail,
range_: nodeCst(method).Range,
selectionRange: nodeCst(method.Name).Range,
})
}
}
} else if function, ok := decl.(*ast.Func); ok && nodeCst(function) != nil && nodeCst(function.Name) != nil {
// Function
detail := ""
Expand Down
5 changes: 0 additions & 5 deletions cmd/lsp/unused.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,6 @@ func (h *handler) Formatting(ctx context.Context, params *protocol.DocumentForma
return nil, errors.New("not implemented")
}

//goland:noinspection GoUnusedParameter
func (h *handler) Implementation(ctx context.Context, params *protocol.ImplementationParams) (result []protocol.Location, err error) {
return nil, errors.New("not implemented")
}

//goland:noinspection GoUnusedParameter
func (h *handler) OnTypeFormatting(ctx context.Context, params *protocol.DocumentOnTypeFormattingParams) (result []protocol.TextEdit, err error) {
return nil, errors.New("not implemented")
Expand Down
48 changes: 43 additions & 5 deletions core/ast/casts.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ const (

Int2Float
Float2Int

Pointer2Interface
)

func GetCast(from, to Type) (CastKind, bool) {
Expand Down Expand Up @@ -50,9 +52,14 @@ func GetCast(from, to Type) (CastKind, bool) {
}
}

// Pointer -> Pointer, Func
// Pointer -> Interface, Pointer, Func
case *Pointer:
switch to.Resolved().(type) {
switch to := to.Resolved().(type) {
case *Interface:
if implements(from, to) {
return Pointer2Interface, true
}

case *Pointer, *Func:
return None, true
}
Expand Down Expand Up @@ -94,12 +101,43 @@ func GetImplicitCast(from, to Type) (CastKind, bool) {
}
}

// Pointer -> Pointer (*void)
// Pointer -> Interface, Pointer (*void)
case *Pointer:
if to, ok := As[*Pointer](to); ok && IsPrimitive(to.Pointee, Void) {
return None, true
switch to := to.Resolved().(type) {
case *Interface:
if implements(from, to) {
return Pointer2Interface, true
}

case *Pointer:
if IsPrimitive(to.Pointee, Void) {
return None, true
}
}
}

return None, false
}

func implements(type_ Type, inter *Interface) bool {
// Check struct pointee
if pointer, ok := type_.(*Pointer); ok {
if s, ok := As[*Struct](pointer.Pointee); ok {
type_ = s
} else {
return false
}
} else {
return false
}

// Get resolver
resolver := GetParent[*File](type_).Resolver

// Check impl
if resolver.GetImpl(type_, inter) != nil {
return true
}

return false
}
Loading

0 comments on commit d6a0b60

Please sign in to comment.