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