15
15
package cxx
16
16
17
17
import (
18
+ "fmt"
19
+ "path/filepath"
20
+ "strings"
21
+
18
22
lsp "github.com/cloudwego/abcoder/lang/lsp"
23
+ "github.com/cloudwego/abcoder/lang/utils"
19
24
)
20
25
21
26
type CxxSpec struct {
@@ -26,56 +31,165 @@ func NewCxxSpec() *CxxSpec {
26
31
return & CxxSpec {}
27
32
}
28
33
34
+ // XXX: maybe multi module support for C++?
29
35
func (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
31
44
}
32
45
46
+ // returns: mod, path, error
33
47
func (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
+
35
59
}
36
60
37
61
func (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"
39
70
}
40
71
41
72
func (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
43
84
}
44
85
45
86
func (c * CxxSpec ) IsEntityToken (tok lsp.Token ) bool {
46
- panic ( "TODO" )
87
+ return tok . Type == "class" || tok . Type == "function" || tok . Type == "variable"
47
88
}
48
89
49
90
func (c * CxxSpec ) IsStdToken (tok lsp.Token ) bool {
50
91
panic ("TODO" )
51
92
}
52
93
53
94
func (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 ))
55
116
}
56
117
57
118
func (c * CxxSpec ) IsMainFunction (sym lsp.DocumentSymbol ) bool {
58
- panic ( "TODO" )
119
+ return sym . Kind == lsp . SKFunction && sym . Name == "main"
59
120
}
60
121
61
122
func (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
64
125
65
- func (c * CxxSpec ) IsPublicSymbol (sym lsp.DocumentSymbol ) bool {
66
- panic ("TODO" )
67
126
}
68
127
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
69
142
func (c * CxxSpec ) HasImplSymbol () bool {
70
- panic ( "TODO" )
143
+ return false
71
144
}
72
145
73
146
func (c * CxxSpec ) ImplSymbol (sym lsp.DocumentSymbol ) (int , int , int ) {
74
147
panic ("TODO" )
75
148
}
76
149
77
150
func (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
79
193
}
80
194
81
195
func (c * CxxSpec ) GetUnloadedSymbol (from lsp.Token , define lsp.Location ) (string , error ) {
0 commit comments