1515package cxx
1616
1717import (
18+ "fmt"
19+ "path/filepath"
20+ "strings"
21+
1822 lsp "github.com/cloudwego/abcoder/lang/lsp"
23+ "github.com/cloudwego/abcoder/lang/utils"
1924)
2025
2126type CxxSpec struct {
@@ -26,56 +31,165 @@ func NewCxxSpec() *CxxSpec {
2631 return & CxxSpec {}
2732}
2833
34+ // XXX: maybe multi module support for C++?
2935func (c * CxxSpec ) WorkSpace (root string ) (map [string ]string , error ) {
30- panic ("TODO" )
36+ c .repo = root
37+ rets := map [string ]string {}
38+ absPath , err := filepath .Abs (root )
39+ if err != nil {
40+ return nil , fmt .Errorf ("failed to get absolute path: %w" , err )
41+ }
42+ rets ["current" ] = absPath
43+ return rets , nil
3144}
3245
46+ // returns: mod, path, error
3347func (c * CxxSpec ) NameSpace (path string ) (string , string , error ) {
34- panic ("TODO" )
48+ // external lib: only standard library (system headers), in /usr/
49+ if ! strings .HasPrefix (path , c .repo ) {
50+ if strings .HasPrefix (path , "/usr" ) {
51+ // assume it is c system library
52+ return "cstdlib" , "cstdlib" , nil
53+ }
54+ panic (fmt .Sprintf ("external lib: %s\n " , path ))
55+ }
56+
57+ return "current" , "current" , nil
58+
3559}
3660
3761func (c * CxxSpec ) ShouldSkip (path string ) bool {
38- panic ("TODO" )
62+ if ! strings .HasSuffix (path , ".c" ) {
63+ return true
64+ }
65+ return false
66+ }
67+
68+ func (c * CxxSpec ) IsDocToken (tok lsp.Token ) bool {
69+ return tok .Type == "comment"
3970}
4071
4172func (c * CxxSpec ) DeclareTokenOfSymbol (sym lsp.DocumentSymbol ) int {
42- panic ("TODO" )
73+ for i , t := range sym .Tokens {
74+ if c .IsDocToken (t ) {
75+ continue
76+ }
77+ for _ , m := range t .Modifiers {
78+ if m == "declaration" {
79+ return i
80+ }
81+ }
82+ }
83+ return - 1
4384}
4485
4586func (c * CxxSpec ) IsEntityToken (tok lsp.Token ) bool {
46- panic ( "TODO" )
87+ return tok . Type == "class" || tok . Type == "function" || tok . Type == "variable"
4788}
4889
4990func (c * CxxSpec ) IsStdToken (tok lsp.Token ) bool {
5091 panic ("TODO" )
5192}
5293
5394func (c * CxxSpec ) TokenKind (tok lsp.Token ) lsp.SymbolKind {
54- panic ("TODO" )
95+ switch tok .Type {
96+ case "class" :
97+ return lsp .SKStruct
98+ case "enum" :
99+ return lsp .SKEnum
100+ case "enumMember" :
101+ return lsp .SKEnumMember
102+ case "function" , "macro" :
103+ return lsp .SKFunction
104+ // rust spec does not treat parameter as a variable
105+ case "parameter" :
106+ return lsp .SKVariable
107+ case "typeParameter" :
108+ return lsp .SKTypeParameter
109+ // type: TODO
110+ case "interface" , "concept" , "method" , "modifier" , "namespace" , "type" :
111+ panic (fmt .Sprintf ("Unsupported token type: %s at %+v\n " , tok .Type , tok .Location ))
112+ case "bracket" , "comment" , "label" , "operator" , "property" , "unknown" :
113+ return lsp .SKUnknown
114+ }
115+ panic (fmt .Sprintf ("Weird token type: %s at %+v\n " , tok .Type , tok .Location ))
55116}
56117
57118func (c * CxxSpec ) IsMainFunction (sym lsp.DocumentSymbol ) bool {
58- panic ( "TODO" )
119+ return sym . Kind == lsp . SKFunction && sym . Name == "main"
59120}
60121
61122func (c * CxxSpec ) IsEntitySymbol (sym lsp.DocumentSymbol ) bool {
62- panic ( "TODO" )
63- }
123+ typ := sym . Kind
124+ return typ == lsp . SKFunction || typ == lsp . SKVariable || typ == lsp . SKClass
64125
65- func (c * CxxSpec ) IsPublicSymbol (sym lsp.DocumentSymbol ) bool {
66- panic ("TODO" )
67126}
68127
128+ func (c * CxxSpec ) IsPublicSymbol (sym lsp.DocumentSymbol ) bool {
129+ id := c .DeclareTokenOfSymbol (sym )
130+ if id == - 1 {
131+ return false
132+ }
133+ for _ , m := range sym .Tokens [id ].Modifiers {
134+ if m == "globalScope" {
135+ return true
136+ }
137+ }
138+ return false
139+ }
140+
141+ // TODO(cpp): support C++ OOP
69142func (c * CxxSpec ) HasImplSymbol () bool {
70- panic ( "TODO" )
143+ return false
71144}
72145
73146func (c * CxxSpec ) ImplSymbol (sym lsp.DocumentSymbol ) (int , int , int ) {
74147 panic ("TODO" )
75148}
76149
77150func (c * CxxSpec ) FunctionSymbol (sym lsp.DocumentSymbol ) (int , []int , []int , []int ) {
78- panic ("TODO" )
151+ // No receiver and no type params for C
152+ if sym .Kind != lsp .SKFunction {
153+ return - 1 , nil , nil , nil
154+ }
155+ receiver := - 1
156+ typeParams := []int {}
157+ inputParams := []int {}
158+ outputs := []int {}
159+
160+ // general format: RETURNVALUE NAME "(" PARAMS ")" BODY
161+ // --------
162+ // fnNameText
163+ // state machine phase 0 phase 1 phase 2: break
164+ // TODO: attributes may contain parens. also inline structs.
165+
166+ endRelOffset := 0
167+ lines := utils .CountLinesCached (sym .Text )
168+ phase := 0
169+ for i , tok := range sym .Tokens {
170+ switch phase {
171+ case 0 :
172+ if tok .Type == "function" {
173+ offset := lsp .RelativePostionWithLines (* lines , sym .Location .Range .Start , tok .Location .Range .Start )
174+ endRelOffset = offset + strings .Index (sym .Text [offset :], ")" )
175+ phase = 1
176+ continue
177+ }
178+ if c .IsEntityToken (tok ) {
179+ outputs = append (outputs , i )
180+ }
181+ case 1 :
182+ offset := lsp .RelativePostionWithLines (* lines , sym .Location .Range .Start , tok .Location .Range .Start )
183+ if offset > endRelOffset {
184+ phase = 2
185+ continue
186+ }
187+ if c .IsEntityToken (tok ) {
188+ inputParams = append (inputParams , i )
189+ }
190+ }
191+ }
192+ return receiver , typeParams , inputParams , outputs
79193}
80194
81195func (c * CxxSpec ) GetUnloadedSymbol (from lsp.Token , define lsp.Location ) (string , error ) {
0 commit comments