]> git.saurik.com Git - cycript.git/blame - Analyze.cpp
Automatically generate FFI bridges using libclang.
[cycript.git] / Analyze.cpp
CommitLineData
8d20f0f1
JF
1#include <cstring>
2#include <iostream>
3#include <map>
4#include <sstream>
5#include <string>
6
7#include <clang-c/Index.h>
8
9struct CYCXString {
10 CXString value_;
11
12 CYCXString(CXString value) :
13 value_(value)
14 {
15 }
16
17 ~CYCXString() {
18 clang_disposeString(value_);
19 }
20
21 operator const char *() const {
22 return clang_getCString(value_);
23 }
24};
25
26struct CYFieldBaton {
27 std::ostringstream types;
28 std::ostringstream names;
29};
30
31static CXChildVisitResult CYFieldVisit(CXCursor cursor, CXCursor parent, CXClientData arg) {
32 CYFieldBaton &baton(*static_cast<CYFieldBaton *>(arg));
33
34 if (clang_getCursorKind(cursor) == CXCursor_FieldDecl) {
35 CXType type(clang_getCursorType(cursor));
36 baton.types << "(typedef " << CYCXString(clang_getTypeSpelling(type)) << "),";
37 baton.names << "'" << CYCXString(clang_getCursorSpelling(cursor)) << "',";
38 }
39
40 return CXChildVisit_Continue;
41}
42
43typedef std::map<std::string, std::string> CYKeyMap;
44
45struct CYChildBaton {
46 CXTranslationUnit unit;
47 CYKeyMap &keys;
48
49 CYChildBaton(CXTranslationUnit unit, CYKeyMap &keys) :
50 unit(unit),
51 keys(keys)
52 {
53 }
54};
55
56struct CYTokens {
57 CXTranslationUnit unit;
58 CXToken *tokens;
59 unsigned count;
60
61 CYTokens(CXTranslationUnit unit, CXCursor cursor) :
62 unit(unit)
63 {
64 CXSourceRange range(clang_getCursorExtent(cursor));
65 clang_tokenize(unit, range, &tokens, &count);
66 }
67
68 ~CYTokens() {
69 clang_disposeTokens(unit, tokens, count);
70 }
71
72 operator CXToken *() const {
73 return tokens;
74 }
75};
76
77static CXChildVisitResult CYChildVisit(CXCursor cursor, CXCursor parent, CXClientData arg) {
78 CYChildBaton &baton(*static_cast<CYChildBaton *>(arg));
79 CXTranslationUnit &unit(baton.unit);
80
81 CYCXString spelling(clang_getCursorSpelling(cursor));
82 std::string name(spelling);
83 std::ostringstream value;
84
85 /*CXSourceLocation location(clang_getCursorLocation(cursor));
86
87 CXFile file;
88 unsigned line;
89 unsigned column;
90 unsigned offset;
91 clang_getSpellingLocation(location, &file, &line, &column, &offset);
92
93 if (file != NULL) {
94 CYCXString path(clang_getFileName(file));
95 std::cout << spelling << " " << path << ":" << line << std::endl;
96 }*/
97
98 switch (clang_getCursorKind(cursor)) {
99 case CXCursor_EnumConstantDecl: {
100 value << clang_getEnumConstantDeclValue(cursor);
101 } break;
102
103 case CXCursor_MacroDefinition: {
104 CYTokens tokens(unit, cursor);
105 if (tokens.count <= 2)
106 goto skip;
107
108 CXCursor cursors[tokens.count];
109 clang_annotateTokens(unit, tokens, tokens.count, cursors);
110
111 for (unsigned i(1); i != tokens.count - 1; ++i) {
112 CYCXString token(clang_getTokenSpelling(unit, tokens[i]));
113 if (i != 1)
114 value << " ";
115 else if (strcmp(token, "(") == 0)
116 goto skip;
117 value << token;
118 }
119 } break;
120
121 case CXCursor_StructDecl: {
122 if (!clang_isCursorDefinition(cursor))
123 goto skip;
124 if (spelling[0] == '\0')
125 goto skip;
126
127 CYFieldBaton baton;
128
129 baton.types << "[";
130 baton.names << "[";
131 clang_visitChildren(cursor, &CYFieldVisit, &baton);
132 baton.types << "]";
133 baton.names << "]";
134
135 name += "$cy";
136 value << "new Type(" << baton.types.str() << "," << baton.names.str() << ")";
137 } break;
138
139 case CXCursor_TypedefDecl: {
140 CXType type(clang_getTypedefDeclUnderlyingType(cursor));
141 value << "(typedef " << CYCXString(clang_getTypeSpelling(type)) << ")";
142 } break;
143
144 case CXCursor_FunctionDecl:
145 case CXCursor_VarDecl: {
146 CXType type(clang_getCursorType(cursor));
147 value << "*(typedef " << CYCXString(clang_getTypeSpelling(type)) << ").pointerTo()(dlsym(RTLD_DEFAULT,'" << spelling << "'))";
148 } break;
149
150 default: {
151 return CXChildVisit_Recurse;
152 } break;
153 }
154
155 baton.keys[name] = value.str();
156
157 skip:
158 return CXChildVisit_Continue;
159}
160
161int main(int argc, const char *argv[]) {
162 CXIndex index(clang_createIndex(0, 0));
163
164 const char *file(argv[1]);
165
166 unsigned offset(3);
167#if CY_OBJECTIVEC
168 argv[--offset] = "-ObjC++";
169#endif
170
171 CXTranslationUnit unit(clang_parseTranslationUnit(index, file, argv + offset, argc - offset, NULL, 0, CXTranslationUnit_DetailedPreprocessingRecord | CXTranslationUnit_SkipFunctionBodies));
172
173 for (unsigned i(0), e(clang_getNumDiagnostics(unit)); i != e; ++i) {
174 CXDiagnostic diagnostic(clang_getDiagnostic(unit, i));
175 CYCXString spelling(clang_getDiagnosticSpelling(diagnostic));
176 std::cerr << spelling << std::endl;
177 }
178
179 CYKeyMap keys;
180 CYChildBaton baton(unit, keys);
181 clang_visitChildren(clang_getTranslationUnitCursor(unit), &CYChildVisit, &baton);
182
183 for (CYKeyMap::const_iterator key(keys.begin()); key != keys.end(); ++key) {
184 std::string value(key->second);
185 for (size_t i(0), e(value.size()); i != e; ++i)
186 if (value[i] <= 0 || value[i] >= 0x7f || value[i] == '\n')
187 goto skip;
188 std::cout << key->first << "|\"" << value << "\"" << std::endl;
189 skip:; }
190
191 clang_disposeTranslationUnit(unit);
192 clang_disposeIndex(index);
193
194 return 0;
195}