Skip to content

Commit 94b3445

Browse files
committed
feat: impl support and export __xx__ for python
1 parent ca86757 commit 94b3445

File tree

2 files changed

+70
-16
lines changed

2 files changed

+70
-16
lines changed

lang/collect/collect.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -174,8 +174,6 @@ func (c *Collector) Collect(ctx context.Context) error {
174174
// only language entity symbols need to be collect on next
175175
if c.spec.IsEntitySymbol(*sym) {
176176
syms = append(syms, sym)
177-
} else {
178-
fmt.Printf("skip %s at %+v with %+v\n", sym.Name, sym.Location, sym.Kind)
179177
}
180178
c.processSymbol(ctx, sym, 1)
181179
}
@@ -548,7 +546,7 @@ func (c *Collector) collectImpl(ctx context.Context, sym *DocumentSymbol, depth
548546
impl = ChunkHead(sym.Text, sym.Location.Range.Start, sym.Tokens[fn].Location.Range.Start)
549547
}
550548
if impl == "" || len(impl) < len(sym.Name) {
551-
impl = sym.Name
549+
impl = fmt.Sprintf("class %s {\n", sym.Name)
552550
}
553551
// search all methods
554552
for _, method := range c.syms {

lang/python/spec.go

Lines changed: 69 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -205,24 +205,81 @@ func (c *PythonSpec) IsEntitySymbol(sym lsp.DocumentSymbol) bool {
205205
}
206206

207207
func (c *PythonSpec) IsPublicSymbol(sym lsp.DocumentSymbol) bool {
208+
// builtin methods are exported
209+
if strings.HasPrefix(sym.Name, "__") && strings.HasSuffix(sym.Name, "__") {
210+
return true
211+
}
208212
if strings.HasPrefix(sym.Name, "_") {
209213
return false
210214
}
211215
return true
212216
}
213217

214218
func (c *PythonSpec) HasImplSymbol() bool {
215-
// Python does not have direct impl symbols
216-
return false
219+
return true
217220
}
218221

222+
func invalidPos() lsp.Position {
223+
return lsp.Position{
224+
Line: -1,
225+
Character: -1,
226+
}
227+
}
228+
229+
// returns interface, receiver, first method
219230
func (c *PythonSpec) ImplSymbol(sym lsp.DocumentSymbol) (int, int, int) {
220-
panic("TODO")
231+
// reference: https://docs.python.org/3/reference/grammar.html
232+
if sym.Kind != lsp.SKClass {
233+
return -1, -1, -1
234+
}
235+
236+
implType := -1
237+
receiverType := -1
238+
firstMethod := -1
239+
240+
// state 0: goto state -1 when we see a 'class'
241+
state := 0
242+
clsnamepos := invalidPos()
243+
curpos := sym.Location.Range.Start
244+
for i := range len(sym.Text) {
245+
if state == -1 {
246+
break
247+
}
248+
switch state {
249+
case 0:
250+
if i+6 >= len(sym.Text) {
251+
// class text does not contain a 'class'
252+
// should be an import
253+
return -1, -1, -1
254+
}
255+
next6chars := sym.Text[i : i+6]
256+
// heuristics should work with reasonable python code
257+
if next6chars == "class " {
258+
clsnamepos = curpos
259+
state = -1
260+
}
261+
}
262+
if sym.Text[i] == '\n' {
263+
curpos.Line++
264+
curpos.Character = 0
265+
} else {
266+
curpos.Character++
267+
}
268+
}
269+
270+
for i, t := range sym.Tokens {
271+
if receiverType == -1 && clsnamepos.Less(t.Location.Range.Start) {
272+
receiverType = i
273+
}
274+
}
275+
276+
return implType, receiverType, firstMethod
221277
}
222278

223279
// returns: receiver, typeParams, inputParams, outputParams
224280
func (c *PythonSpec) FunctionSymbol(sym lsp.DocumentSymbol) (int, []int, []int, []int) {
225-
// no receiver. no type params in python
281+
// FunctionSymbol do not return receivers.
282+
// TODO type params in python (nobody uses them)
226283
// reference: https://docs.python.org/3/reference/grammar.html
227284
receiver := -1
228285
// python actually has these but TODO
@@ -239,20 +296,19 @@ func (c *PythonSpec) FunctionSymbol(sym lsp.DocumentSymbol) (int, []int, []int,
239296
// finish when we see a :
240297
state := 0
241298
paren_depth := 0
242-
invalidpos := lsp.Position{
243-
Line: -1,
244-
Character: -1,
245-
}
246-
// defpos := invalidpos
247-
lparenpos := invalidpos
248-
rparenpos := invalidpos
249-
bodypos := invalidpos
299+
// defpos := invalidPos()
300+
lparenpos := invalidPos()
301+
rparenpos := invalidPos()
302+
bodypos := invalidPos()
250303
curpos := sym.Location.Range.Start
251304
for i := range len(sym.Text) {
305+
if state == -1 {
306+
break
307+
}
252308
switch state {
253309
case 0:
254310
if i+4 >= len(sym.Text) {
255-
// function text does not contain a def
311+
// function text does not contain a 'def'
256312
// should be an import
257313
return -1, []int{}, []int{}, []int{}
258314
}

0 commit comments

Comments
 (0)