1
- #include " TypeTranslator.h"
2
- #include " HeaderManager.h"
3
- #include " Utils.h"
4
-
5
- #include " clang/Driver/Options.h"
6
- #include " clang/Basic/LangOptions.h"
7
- #include " clang/AST/AST.h"
8
- #include " clang/AST/ASTContext.h"
9
- #include " clang/AST/ASTConsumer.h"
10
- #include " clang/AST/RecursiveASTVisitor.h"
11
- #include " clang/Frontend/ASTConsumers.h"
12
- #include " clang/Frontend/FrontendActions.h"
13
- #include " clang/Frontend/CompilerInstance.h"
14
- #include " clang/Tooling/CommonOptionsParser.h"
15
- #include " clang/Tooling/Tooling.h"
16
- #include " llvm/Support/CommandLine.h"
17
-
18
- #include < iostream>
1
+ #include " ScalaBindgen.h"
19
2
20
3
#define SCALA_NATIVE_MAX_STRUCT_FIELDS 22
21
4
22
5
static llvm::cl::OptionCategory Category (" Binding Generator" );
23
6
static llvm::cl::extrahelp CommonHelp (clang::tooling::CommonOptionsParser::HelpMessage);
24
7
static llvm::cl::extrahelp MoreHelp (" \n Produce Bindings for scala native. Please specify lib name wit parameter name\n " );
25
8
static llvm::cl::opt<std::string> LibName (" name" , llvm::cl::cat(Category));
9
+ static llvm::cl::opt<std::string> StdHeaders (" stdHeaders" , llvm::cl::cat(Category));
10
+
26
11
27
12
HeaderManager headerMan;
28
13
29
14
std::string declarations;
30
15
std::string enums;
31
16
32
- class TreeVisitor : public clang ::RecursiveASTVisitor<TreeVisitor> {
33
- private:
34
- clang::ASTContext* astContext;
35
- TypeTranslator typeTranslator;
36
-
37
- public:
38
- explicit TreeVisitor (clang::CompilerInstance *CI) : astContext(&(CI->getASTContext ())), typeTranslator(astContext) {}
39
-
40
- virtual bool VisitFunctionDecl (clang::FunctionDecl *func) {
41
- std::string funcName = func->getNameInfo ().getName ().getAsString ();
42
- std::string retType = typeTranslator.Translate (func->getReturnType ());
43
- std::string params = " " ;
44
-
45
- for (const clang::ParmVarDecl* parm : func->parameters ()){
46
- // Handle default values
47
- std::string pname = parm->getNameAsString ();
48
- if (pname == " " ){
49
- pname = " anonymous" ;
50
- }
51
- params += pname;
52
- params += " : " ;
53
- params += typeTranslator.Translate (parm->getType ());
54
- params += " , " ;
55
- }
56
-
57
- // remove last ,
58
- if (params != " " ){
59
- params = params.substr (0 , params.size ()-2 );
60
- }
61
-
62
- declarations += " \t def " + funcName + " (" + params + " ): " + retType + " = native.extern\n " ;
63
- return true ;
17
+ bool TreeVisitor::VisitFunctionDecl (clang::FunctionDecl *func) {
18
+ std::string funcName = func->getNameInfo ().getName ().getAsString ();
19
+ std::string retType = typeTranslator.Translate (func->getReturnType ());
20
+ std::string params = " " ;
21
+
22
+ for (const clang::ParmVarDecl* parm : func->parameters ()){
23
+ // Handle default values
24
+ std::string pname = parm->getNameAsString ();
25
+ if (pname == " " ){
26
+ pname = " anonymous" ;
27
+ }
28
+ params += pname;
29
+ params += " : " ;
30
+ params += typeTranslator.Translate (parm->getType ());
31
+ params += " , " ;
64
32
}
65
33
66
- virtual bool VisitTypedefDecl (clang::TypedefDecl *tpdef){
67
- std::string name = tpdef->getName ();
68
- std::string tpe = typeTranslator.Translate (tpdef->getUnderlyingType ());
69
- declarations += " \t type " + name + " = " + tpe + " \n " ;
70
- return true ;
34
+ // remove last ,
35
+ if (params != " " ){
36
+ params = params.substr (0 , params.size ()-2 );
71
37
}
72
38
73
- virtual bool VisitEnumDecl (clang::EnumDecl *enumdecl){
74
- std::string name = enumdecl->getNameAsString ();
39
+ declarations += " \t def " + funcName + " (" + params + " ): " + retType + " = native.extern\n " ;
40
+ return true ;
41
+ }
75
42
76
- // Replace "enum x" with enum_x in scala
77
- typeTranslator.AddTranslation (" enum " + name, " enum_" + name);
43
+ bool TreeVisitor::VisitTypedefDecl (clang::TypedefDecl *tpdef){
44
+ std::string name = tpdef->getName ();
45
+ std::string tpe = typeTranslator.Translate (tpdef->getUnderlyingType ());
46
+ declarations += " \t type " + name + " = " + tpe + " \n " ;
47
+ return true ;
48
+ }
78
49
79
- if (name == " " && enumdecl->getTypedefNameForAnonDecl ()){
80
- name = enumdecl->getTypedefNameForAnonDecl ()->getNameAsString ();
81
- }
50
+ bool TreeVisitor::VisitEnumDecl (clang::EnumDecl *enumdecl){
51
+ std::string name = enumdecl->getNameAsString ();
82
52
83
- if (name != " " ){
84
- declarations += " \t type enum_" + name + " = native.CInt\n " ;
85
- }
86
-
87
- int i = 0 ;
88
- for (const clang::EnumConstantDecl* en : enumdecl->enumerators ()){
89
- if (name != " " ){
90
- enums += " \t final val enum_" + name + " _" + en->getNameAsString () + " = " + std::to_string (i++) + " \n " ;
91
- } else {
92
- enums += " \t final val enum_" + en->getNameAsString () + " = " + std::to_string (i++) + " \n " ;
93
- }
94
- }
53
+ // Replace "enum x" with enum_x in scala
54
+ typeTranslator.AddTranslation (" enum " + name, " enum_" + name);
95
55
96
- return true ;
56
+ if (name == " " && enumdecl->getTypedefNameForAnonDecl ()){
57
+ name = enumdecl->getTypedefNameForAnonDecl ()->getNameAsString ();
97
58
}
98
59
99
- virtual bool VisitRecordDecl (clang::RecordDecl *record){
100
- std::string name = record->getNameAsString ();
60
+ if (name != " " ){
61
+ declarations += " \t type enum_" + name + " = native.CInt\n " ;
62
+ }
101
63
102
- // Handle typedef struct {} x; and typedef union {} y; by getting the name from the typedef
103
- if ((record->isStruct () || record->isUnion ()) && name == " " && record->getTypedefNameForAnonDecl ()){
104
- name = record->getTypedefNameForAnonDecl ()->getNameAsString ();
64
+ int i = 0 ;
65
+ for (const clang::EnumConstantDecl* en : enumdecl->enumerators ()){
66
+ if (name != " " ){
67
+ enums += " \t final val enum_" + name + " _" + en->getNameAsString () + " = " + std::to_string (i++) + " \n " ;
68
+ } else {
69
+ enums += " \t final val enum_" + en->getNameAsString () + " = " + std::to_string (i++) + " \n " ;
105
70
}
71
+ }
106
72
107
- if (record->isUnion () && !record->isAnonymousStructOrUnion () && name != " " ){
108
-
109
- // Replace "union x" with union_x in scala
110
- typeTranslator.AddTranslation (" union " + name, " union" + name);
111
-
112
- uint64_t maxSize = 0 ;
73
+ return true ;
74
+ }
113
75
114
- for (const clang::FieldDecl* field : record->fields ()){
115
- maxSize = std::max (maxSize, astContext->getTypeSize (field->getType ()));
116
- }
76
+ bool TreeVisitor::VisitRecordDecl (clang::RecordDecl *record){
77
+ std::string name = record->getNameAsString ();
117
78
118
- declarations += " \t type union_" + name + " = native.CArray[Byte, " + intToScalaNat (maxSize) + " ]\n " ;
79
+ // Handle typedef struct {} x; and typedef union {} y; by getting the name from the typedef
80
+ if ((record->isStruct () || record->isUnion ()) && name == " " && record->getTypedefNameForAnonDecl ()){
81
+ name = record->getTypedefNameForAnonDecl ()->getNameAsString ();
82
+ }
119
83
120
- return true ;
84
+ if (record-> isUnion () && !record-> isAnonymousStructOrUnion () && name != " " ){
121
85
122
- } else if (record->isStruct () && record->isThisDeclarationADefinition () && !record->isAnonymousStructOrUnion () && name != " " ){
86
+ // Replace "union x" with union_x in scala
87
+ typeTranslator.AddTranslation (" union " + name, " union" + name);
123
88
124
- // Replace "struct x" with struct_x in scala
125
- typeTranslator.AddTranslation (" struct " + name, " struct_" +name);
89
+ uint64_t maxSize = 0 ;
126
90
127
- int counter = 0 ;
128
- std::string fields = " " ;
91
+ for (const clang::FieldDecl* field : record->fields ()){
92
+ maxSize = std::max (maxSize, astContext->getTypeSize (field->getType ()));
93
+ }
129
94
130
- for (const clang::FieldDecl* field : record->fields ()){
131
- fields += typeTranslator.Translate (field->getType (), &name) + " ," ;
132
- counter++;
133
- }
95
+ declarations += " \t type union_" + name + " = native.CArray[Byte, " + intToScalaNat (maxSize) + " ]\n " ;
134
96
135
- // remove last ,
136
- if (fields != " " ){
137
- fields = fields.substr (0 , fields.size ()-1 );
138
- }
97
+ return true ;
139
98
140
- if (counter < SCALA_NATIVE_MAX_STRUCT_FIELDS){
141
- declarations += " \t type struct_" + name + " = " + " native.CStruct" + std::to_string (counter) + " [" + fields + " ]\n " ;
142
- } else {
143
- // There is no easy way to represent it as a struct in scala native, have to represent it as an array and then
144
- // Add helpers to help with it's manipulation
145
- uint64_t size = astContext->getTypeSize (record->getTypeForDecl ());
146
- declarations += " \t type struct_" + name + " = " + " native.CArray[Byte, " + uint64ToScalaNat (size) + " ]\n " ;
147
- }
99
+ } else if (record->isStruct () && record->isThisDeclarationADefinition () && !record->isAnonymousStructOrUnion () && name != " " ){
148
100
149
- return true ;
150
- }
151
- return false ;
152
- }
101
+ // Replace "struct x" with struct_x in scala
102
+ typeTranslator.AddTranslation (" struct " + name, " struct_" +name);
153
103
154
- };
155
-
156
-
157
-
158
- class TreeConsumer : public clang ::ASTConsumer {
159
- private:
160
- TreeVisitor *visitor;
161
- clang::SourceManager& smanager;
162
-
163
- public:
164
-
165
- std::vector<std::string> stdheaders{" assert.h" ," complex.h" ," ctype.h" ," errno.h" ," fenv.h" ," float.h" ," inttypes.h" ," iso646.h" ," limits.h" ,
166
- " locale.h" ," math.h" ," setjmp.h" ," signal.h" ," stdalign.h" ," stdarg.h" ," stdatomic.h" ," stdbool.h" ," stddef.h" ,
167
- " stdint.h" ," stdio.h" ," stdlib.h" ," stdnoreturn.h" ," string.h" ," tgmath.h" ," threads.h" ," time.h" ," uchar.h" ,
168
- " wchar.h" ," wctype.h" ," aio.h" ," inet.h" ," assert.h" ," complex.h" ," cpio.h" ," ctype.h" ," dirent.h" ," dlfcn.h" ,
169
- " errno.h" ," fcntl.h" ," fenv.h" ," float.h" ," fmtmsg.h" ," fnmatch.h" ," ftw.h" ," glob.h" ," grp.h" ," iconv.h" ,
170
- " inttypes.h" ," iso646.h" ," langinfo.h" ," libgen.h" ," limits.h" ," locale.h" ," math.h" ," monetary.h" ," mqueue.h" ,
171
- " ndbm.h" ," if.h" ," netdb.h" ," in.h" ," tcp.h" ," nl_types.h" ," poll.h" ," pthread.h" ," pwd.h" ,
172
- " regex.h" ," sched.h" ," search.h" ," semaphore.h" ," setjmp.h" ," signal.h" ," spawn.h" ," stdarg.h" ," stdbool.h" ,
173
- " stddef.h" ," stdint.h" ," stdio.h" ," stdlib.h" ," string.h" ," strings.h" ," stropts.h" ," ipc.h" ," mman.h" ,
174
- " msg.h" ," resource.h" ," select.h" ," sem.h" ," shm.h" ," socket.h" ," stat.h" ,
175
- " statvfs.h" ," time.h" ," times.h" ," types.h" ," uio.h" ," un.h" ," utsname.h" ,
176
- " wait.h" ," syslog.h" ," tar.h" ," termios.h" ," tgmath.h" ," time.h" ," trace.h" ," ulimit.h" ," unistd.h" ,
177
- " utime.h" ," utmpx.h" ," wchar.h" ," wctype.h" ," wordexp.h" ,
178
-
179
- " siginfo.h" , " sigset.h" , " sigaction.h" , " sigcontext.h" , " sigthread.h" , " ucontext.h" ,
180
- " pthreadtypes.h" , " libio.h" , " __stddef_max_align_t.h" , " _G_config.h" , " sys_errlist.h" ,
181
- " sysmacros.h" , " xlocale.h" , " socket_type.h" , " sockaddr.h" , " sigstack.h"
182
- };
183
-
184
- /* with folders
185
- std::vector<std::string> stdheaders{"assert.h","complex.h","ctype.h","errno.h","fenv.h","float.h","inttypes.h","iso646.h","limits.h",
186
- "locale.h","math.h","setjmp.h","signal.h","stdalign.h","stdarg.h","stdatomic.h","stdbool.h","stddef.h",
187
- "stdint.h","stdio.h","stdlib.h","stdnoreturn.h","string.h","tgmath.h","threads.h","time.h","uchar.h",
188
- "wchar.h","wctype.h","aio.h","arpa/inet.h","assert.h","complex.h","cpio.h","ctype.h","dirent.h","dlfcn.h",
189
- "errno.h","fcntl.h","fenv.h","float.h","fmtmsg.h","fnmatch.h","ftw.h","glob.h","grp.h","iconv.h",
190
- "inttypes.h","iso646.h","langinfo.h","libgen.h","limits.h","locale.h","math.h","monetary.h","mqueue.h",
191
- "ndbm.h","net/if.h","netdb.h","netinet/in.h","netinet/tcp.h","nl_types.h","poll.h","pthread.h","pwd.h",
192
- "regex.h","sched.h","search.h","semaphore.h","setjmp.h","signal.h","spawn.h","stdarg.h","stdbool.h",
193
- "stddef.h","stdint.h","stdio.h","stdlib.h","string.h","strings.h","stropts.h","sys/ipc.h","sys/mman.h",
194
- "sys/msg.h","sys/resource.h","sys/select.h","sys/sem.h","sys/shm.h","sys/socket.h","sys/stat.h",
195
- "sys/statvfs.h","sys/time.h","sys/times.h","sys/types.h","sys/uio.h","sys/un.h","sys/utsname.h",
196
- "sys/wait.h","syslog.h","tar.h","termios.h","tgmath.h","time.h","trace.h","ulimit.h","unistd.h",
197
- "utime.h","utmpx.h","wchar.h","wctype.h","wordexp.h"};
198
- */
199
-
200
- explicit TreeConsumer (clang::CompilerInstance *CI) : visitor(new TreeVisitor(CI)), smanager(CI->getASTContext ().getSourceManager()) {}
201
-
202
- std::string basename (const std::string& pathname) {
203
- return {std::find_if (pathname.rbegin (), pathname.rend (),
204
- [](char c) { return c == ' /' ; }).base (),
205
- pathname.end ()};
206
- }
104
+ int counter = 0 ;
105
+ std::string fields = " " ;
207
106
208
- virtual bool HandleTopLevelDecl (clang::DeclGroupRef DG) {
209
- // a DeclGroupRef may have multiple Decls, so we iterate through each one
210
- for (clang::DeclGroupRef::iterator i = DG.begin (), e = DG.end (); i != e; i++) {
211
- clang::Decl *D = *i;
212
- std::string fpath = smanager.getFilename (D->getLocation ()).str ();
213
- if (std::find (stdheaders.begin (), stdheaders.end (), basename (fpath)) == stdheaders.end ()){
214
- visitor->TraverseDecl (D); // recursively visit each AST node in Decl "D"
215
- }
107
+ for (const clang::FieldDecl* field : record->fields ()){
108
+ fields += typeTranslator.Translate (field->getType (), &name) + " ," ;
109
+ counter++;
216
110
}
217
- return true ;
218
- }
219
-
220
- // this replaces "HandleTopLevelDecl"
221
- // override this to call our ExampleVisitor on the entire source file
222
- /* virtual void HandleTranslationUnit(clang::ASTContext &Context) {
223
- //we can use ASTContext to get the TranslationUnitDecl, which is
224
- //a single Decl that collectively represents the entire source file
225
- visitor->TraverseDecl(Context.getTranslationUnitDecl());
226
- }*/
227
-
228
- };
229
111
112
+ // remove last ,
113
+ if (fields != " " ){
114
+ fields = fields.substr (0 , fields.size ()-1 );
115
+ }
230
116
117
+ if (counter < SCALA_NATIVE_MAX_STRUCT_FIELDS){
118
+ declarations += " \t type struct_" + name + " = " + " native.CStruct" + std::to_string (counter) + " [" + fields + " ]\n " ;
119
+ } else {
120
+ // There is no easy way to represent it as a struct in scala native, have to represent it as an array and then
121
+ // Add helpers to help with it's manipulation
122
+ uint64_t size = astContext->getTypeSize (record->getTypeForDecl ());
123
+ declarations += " \t type struct_" + name + " = " + " native.CArray[Byte, " + uint64ToScalaNat (size) + " ]\n " ;
124
+ }
231
125
232
- class ExampleFrontendAction : public clang ::ASTFrontendAction {
233
- public:
234
- virtual std::unique_ptr<clang::ASTConsumer> CreateASTConsumer (clang::CompilerInstance &CI, clang::StringRef file) {
235
- return std::unique_ptr<clang::ASTConsumer>(new TreeConsumer (&CI)); // pass CI pointer to ASTConsumer
126
+ return true ;
236
127
}
237
- };
128
+ return false ;
129
+ }
130
+
238
131
239
132
240
133
int main (int argc, const char **argv) {
@@ -247,11 +140,14 @@ int main(int argc, const char **argv) {
247
140
return -1 ;
248
141
}
249
142
143
+ auto stdhead = StdHeaders.getValue ();
144
+ if (stdhead != " " ){
145
+ headerMan.LoadConfig (stdhead);
146
+ }
147
+
250
148
declarations = " " ;
251
149
enums = " " ;
252
150
253
- headerMan.LoadConfig (std::string (" ../llvm/tools/clang/tools/extra/scala-bindgen/nativeHeaders.txt" ));
254
-
255
151
256
152
int result = Tool.run (clang::tooling::newFrontendActionFactory<ExampleFrontendAction>().get ());
257
153
0 commit comments