]> git.saurik.com Git - cycript.git/blob - Analyze.cpp
c6e5777e59b1d873078c56c015850c7aab4f3e84
[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
142 baton.types << "[";
143 baton.names << "[";
144 clang_visitChildren(cursor, &CYFieldVisit, &baton);
145 baton.types << "]";
146 baton.names << "]";
147
148 name += "$cy";
149 value << "new Type(" << baton.types.str() << "," << baton.names.str() << ")";
150 } break;
151
152 case CXCursor_TypedefDecl: {
153 CXType type(clang_getTypedefDeclUnderlyingType(cursor));
154 value << "(typedef " << CYCXString(clang_getTypeSpelling(type)) << ")";
155 } break;
156
157 case CXCursor_FunctionDecl:
158 case CXCursor_VarDecl: {
159 CYAttributeBaton baton;
160 clang_visitChildren(cursor, &CYAttributeVisit, &baton);
161
162 if (baton.label.empty()) {
163 baton.label = spelling;
164 baton.label = '_' + baton.label;
165 } else if (baton.label[0] != '_')
166 goto skip;
167
168 CXType type(clang_getCursorType(cursor));
169 value << "*(typedef " << CYCXString(clang_getTypeSpelling(type)) << ").pointerTo()(dlsym(RTLD_DEFAULT,'" << baton.label.substr(1) << "'))";
170 } break;
171
172 default: {
173 return CXChildVisit_Recurse;
174 } break;
175 }
176
177 baton.keys[name] = value.str();
178
179 skip:
180 return CXChildVisit_Continue;
181 }
182
183 int main(int argc, const char *argv[]) {
184 CXIndex index(clang_createIndex(0, 0));
185
186 const char *file(argv[1]);
187
188 unsigned offset(3);
189 #if CY_OBJECTIVEC
190 argv[--offset] = "-ObjC++";
191 #endif
192
193 CXTranslationUnit unit(clang_parseTranslationUnit(index, file, argv + offset, argc - offset, NULL, 0, CXTranslationUnit_DetailedPreprocessingRecord | CXTranslationUnit_SkipFunctionBodies));
194
195 for (unsigned i(0), e(clang_getNumDiagnostics(unit)); i != e; ++i) {
196 CXDiagnostic diagnostic(clang_getDiagnostic(unit, i));
197 CYCXString spelling(clang_getDiagnosticSpelling(diagnostic));
198 std::cerr << spelling << std::endl;
199 }
200
201 CYKeyMap keys;
202 CYChildBaton baton(unit, keys);
203 clang_visitChildren(clang_getTranslationUnitCursor(unit), &CYChildVisit, &baton);
204
205 for (CYKeyMap::const_iterator key(keys.begin()); key != keys.end(); ++key) {
206 std::string value(key->second);
207 for (size_t i(0), e(value.size()); i != e; ++i)
208 if (value[i] <= 0 || value[i] >= 0x7f || value[i] == '\n')
209 goto skip;
210 std::cout << key->first << "|\"" << value << "\"" << std::endl;
211 skip:; }
212
213 clang_disposeTranslationUnit(unit);
214 clang_disposeIndex(index);
215
216 return 0;
217 }