]> git.saurik.com Git - cycript.git/blame - Analyze.cpp
Convert static inline functions into bridge stubs.
[cycript.git] / Analyze.cpp
CommitLineData
2e43a0b0
JF
1/* Cycript - Optimizing JavaScript Compiler/Runtime
2 * Copyright (C) 2009-2015 Jay Freeman (saurik)
3*/
4
5/* GNU Affero General Public License, Version 3 {{{ */
6/*
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Affero General Public License for more details.
16
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19**/
20/* }}} */
21
8d20f0f1
JF
22#include <cstring>
23#include <iostream>
24#include <map>
25#include <sstream>
26#include <string>
27
28#include <clang-c/Index.h>
29
2e43a0b0
JF
30#include "Functor.hpp"
31#include "Replace.hpp"
32#include "Syntax.hpp"
33
34static CXChildVisitResult CYVisit(CXCursor cursor, CXCursor parent, CXClientData arg) {
35 (*reinterpret_cast<const Functor<void (CXCursor)> *>(arg))(cursor);
36 return CXChildVisit_Continue;
37}
38
39static unsigned CYForChild(CXCursor cursor, const Functor<void (CXCursor)> &visitor) {
40 return clang_visitChildren(cursor, &CYVisit, const_cast<void *>(static_cast<const void *>(&visitor)));
41}
42
43static bool CYOneChild(CXCursor cursor, const Functor<void (CXCursor)> &visitor) {
44 bool visited(false);
45 CYForChild(cursor, fun([&](CXCursor child) {
46 _assert(!visited);
47 visited = true;
48 visitor(child);
49 }));
50 return visited;
51}
52
8d20f0f1
JF
53struct CYCXString {
54 CXString value_;
55
56 CYCXString(CXString value) :
57 value_(value)
58 {
59 }
60
2e43a0b0
JF
61 CYCXString(CXCursor cursor) :
62 value_(clang_getCursorSpelling(cursor))
63 {
64 }
65
66 CYCXString(CXCursorKind kind) :
67 value_(clang_getCursorKindSpelling(kind))
68 {
69 }
70
71 CYCXString(CXTranslationUnit unit, CXToken token) :
72 value_(clang_getTokenSpelling(unit, token))
73 {
74 }
75
8d20f0f1
JF
76 ~CYCXString() {
77 clang_disposeString(value_);
78 }
79
80 operator const char *() const {
81 return clang_getCString(value_);
82 }
8d20f0f1 83
2e43a0b0
JF
84 const char *Pool(CYPool &pool) const {
85 return pool.strdup(*this);
8d20f0f1 86 }
b7854baa
JF
87};
88
8d20f0f1
JF
89typedef std::map<std::string, std::string> CYKeyMap;
90
91struct CYChildBaton {
92 CXTranslationUnit unit;
93 CYKeyMap &keys;
94
95 CYChildBaton(CXTranslationUnit unit, CYKeyMap &keys) :
96 unit(unit),
97 keys(keys)
98 {
99 }
100};
101
102struct CYTokens {
103 CXTranslationUnit unit;
104 CXToken *tokens;
105 unsigned count;
106
107 CYTokens(CXTranslationUnit unit, CXCursor cursor) :
108 unit(unit)
109 {
110 CXSourceRange range(clang_getCursorExtent(cursor));
111 clang_tokenize(unit, range, &tokens, &count);
112 }
113
114 ~CYTokens() {
115 clang_disposeTokens(unit, tokens, count);
116 }
117
118 operator CXToken *() const {
119 return tokens;
120 }
121};
122
2e43a0b0
JF
123static CYExpression *CYTranslateExpression(CXTranslationUnit unit, CXCursor cursor) {
124 switch (CXCursorKind kind = clang_getCursorKind(cursor)) {
125 case CXCursor_CallExpr: {
126 CYExpression *function(NULL);
127 CYList<CYArgument> arguments;
128 CYForChild(cursor, fun([&](CXCursor child) {
129 CYExpression *expression(CYTranslateExpression(unit, child));
130 if (function == NULL)
131 function = expression;
132 else
133 arguments->*$C_(expression);
134 }));
135 return $C(function, arguments);
136 } break;
137
138 case CXCursor_DeclRefExpr: {
139 return $V(CYCXString(cursor).Pool($pool));
140 } break;
141
142 case CXCursor_IntegerLiteral: {
143 CYTokens tokens(unit, cursor);
144 _assert(tokens.count != 0);
145 // XXX: I don't understand why this is often enormous :/
146 return $ CYNumber(CYCastDouble(CYCXString(unit, tokens[0])));
147 } break;
148
149 case CXCursor_CStyleCastExpr:
150 // XXX: most of the time, this is a "NoOp" integer cast; but we should check it
151
152 case CXCursor_UnexposedExpr:
153 // there is a very high probability that this is actually an "ImplicitCastExpr"
154 // "Douglas Gregor" <dgregor@apple.com> err'd on the incorrect side of this one
155 // http://lists.llvm.org/pipermail/cfe-commits/Week-of-Mon-20110926/046998.html
156
157 case CXCursor_ParenExpr: {
158 CYExpression *pass(NULL);
159 CYOneChild(cursor, fun([&](CXCursor child) {
160 pass = CYTranslateExpression(unit, child);
161 }));
162 return pass;
163 } break;
164
165 default:
166 //std::cerr << "E:" << CYCXString(kind) << std::endl;
167 _assert(false);
168 }
169}
170
171static CYStatement *CYTranslateStatement(CXTranslationUnit unit, CXCursor cursor) {
172 switch (CXCursorKind kind = clang_getCursorKind(cursor)) {
173 case CXCursor_ReturnStmt: {
174 CYExpression *value(NULL);
175 CYOneChild(cursor, fun([&](CXCursor child) {
176 value = CYTranslateExpression(unit, child);
177 }));
178 return $ CYReturn(value);
179 } break;
180
181 default:
182 //std::cerr << "S:" << CYCXString(kind) << std::endl;
183 _assert(false);
184 }
185}
186
187static CYStatement *CYTranslateBlock(CXTranslationUnit unit, CXCursor cursor) {
188 CYList<CYStatement> statements;
189 CYForChild(cursor, fun([&](CXCursor child) {
190 statements->*CYTranslateStatement(unit, child);
191 }));
192 return $ CYBlock(statements);
193}
194
8d20f0f1
JF
195static CXChildVisitResult CYChildVisit(CXCursor cursor, CXCursor parent, CXClientData arg) {
196 CYChildBaton &baton(*static_cast<CYChildBaton *>(arg));
197 CXTranslationUnit &unit(baton.unit);
198
2e43a0b0 199 CYCXString spelling(cursor);
8d20f0f1
JF
200 std::string name(spelling);
201 std::ostringstream value;
202
203 /*CXSourceLocation location(clang_getCursorLocation(cursor));
204
205 CXFile file;
206 unsigned line;
207 unsigned column;
208 unsigned offset;
209 clang_getSpellingLocation(location, &file, &line, &column, &offset);
210
211 if (file != NULL) {
212 CYCXString path(clang_getFileName(file));
213 std::cout << spelling << " " << path << ":" << line << std::endl;
214 }*/
215
2e43a0b0 216 switch (CXCursorKind kind = clang_getCursorKind(cursor)) {
8d20f0f1
JF
217 case CXCursor_EnumConstantDecl: {
218 value << clang_getEnumConstantDeclValue(cursor);
219 } break;
220
221 case CXCursor_MacroDefinition: {
222 CYTokens tokens(unit, cursor);
223 if (tokens.count <= 2)
224 goto skip;
225
226 CXCursor cursors[tokens.count];
227 clang_annotateTokens(unit, tokens, tokens.count, cursors);
228
229 for (unsigned i(1); i != tokens.count - 1; ++i) {
2e43a0b0 230 CYCXString token(unit, tokens[i]);
8d20f0f1
JF
231 if (i != 1)
232 value << " ";
233 else if (strcmp(token, "(") == 0)
234 goto skip;
235 value << token;
236 }
237 } break;
238
239 case CXCursor_StructDecl: {
240 if (!clang_isCursorDefinition(cursor))
241 goto skip;
242 if (spelling[0] == '\0')
243 goto skip;
244
2e43a0b0
JF
245 std::ostringstream types;
246 std::ostringstream names;
247
248 CYForChild(cursor, fun([&](CXCursor child) {
249 if (clang_getCursorKind(child) == CXCursor_FieldDecl) {
250 CXType type(clang_getCursorType(child));
251 types << "(typedef " << CYCXString(clang_getTypeSpelling(type)) << "),";
252 names << "'" << CYCXString(child) << "',";
253 }
254 }));
8d20f0f1
JF
255
256 name += "$cy";
2e43a0b0 257 value << "new Type([" << types.str() << "],[" << names.str() << "])";
8d20f0f1
JF
258 } break;
259
260 case CXCursor_TypedefDecl: {
261 CXType type(clang_getTypedefDeclUnderlyingType(cursor));
262 value << "(typedef " << CYCXString(clang_getTypeSpelling(type)) << ")";
263 } break;
264
265 case CXCursor_FunctionDecl:
2e43a0b0
JF
266 case CXCursor_VarDecl: try {
267 std::string label;
268
269 CYList<CYFunctionParameter> parameters;
270 CYStatement *code(NULL);
271
272 CYLocalPool local;
273
274 CYForChild(cursor, fun([&](CXCursor child) {
275 switch (CXCursorKind kind = clang_getCursorKind(child)) {
276 case CXCursor_AsmLabelAttr:
277 label = CYCXString(child);
278 break;
279
280 case CXCursor_CompoundStmt:
281 code = CYTranslateBlock(unit, child);
282 break;
283
284 case CXCursor_ParmDecl:
285 parameters->*$P($B($I(CYCXString(child).Pool($pool))));
286 break;
287
288 case CXCursor_IntegerLiteral:
289 case CXCursor_ObjCClassRef:
290 case CXCursor_TypeRef:
291 case CXCursor_UnexposedAttr:
292 break;
293
294 default:
295 std::cerr << "A:" << CYCXString(child) << std::endl;
296 break;
297 }
298 }));
299
300 if (label.empty()) {
301 label = spelling;
302 label = '_' + label;
303 } else if (label[0] != '_')
b7854baa
JF
304 goto skip;
305
2e43a0b0
JF
306 if (code == NULL) {
307 CXType type(clang_getCursorType(cursor));
308 value << "*(typedef " << CYCXString(clang_getTypeSpelling(type)) << ").pointerTo()(dlsym(RTLD_DEFAULT,'" << label.substr(1) << "'))";
309 } else {
310 CYOptions options;
311 CYOutput out(*value.rdbuf(), options);
312 CYFunctionExpression *function($ CYFunctionExpression(NULL, parameters, code));
313 function->Output(out, CYNoBFC);
314 //std::cerr << value.str() << std::endl;
315 }
316 } catch (const CYException &error) {
317 CYPool pool;
318 //std::cerr << error.PoolCString(pool) << std::endl;
319 goto skip;
8d20f0f1
JF
320 } break;
321
322 default: {
323 return CXChildVisit_Recurse;
324 } break;
325 }
326
327 baton.keys[name] = value.str();
328
329 skip:
330 return CXChildVisit_Continue;
331}
332
333int main(int argc, const char *argv[]) {
334 CXIndex index(clang_createIndex(0, 0));
335
336 const char *file(argv[1]);
337
338 unsigned offset(3);
339#if CY_OBJECTIVEC
340 argv[--offset] = "-ObjC++";
341#endif
342
2e43a0b0 343 CXTranslationUnit unit(clang_parseTranslationUnit(index, file, argv + offset, argc - offset, NULL, 0, CXTranslationUnit_DetailedPreprocessingRecord));
8d20f0f1
JF
344
345 for (unsigned i(0), e(clang_getNumDiagnostics(unit)); i != e; ++i) {
346 CXDiagnostic diagnostic(clang_getDiagnostic(unit, i));
347 CYCXString spelling(clang_getDiagnosticSpelling(diagnostic));
348 std::cerr << spelling << std::endl;
349 }
350
351 CYKeyMap keys;
352 CYChildBaton baton(unit, keys);
353 clang_visitChildren(clang_getTranslationUnitCursor(unit), &CYChildVisit, &baton);
354
355 for (CYKeyMap::const_iterator key(keys.begin()); key != keys.end(); ++key) {
356 std::string value(key->second);
357 for (size_t i(0), e(value.size()); i != e; ++i)
358 if (value[i] <= 0 || value[i] >= 0x7f || value[i] == '\n')
359 goto skip;
360 std::cout << key->first << "|\"" << value << "\"" << std::endl;
361 skip:; }
362
363 clang_disposeTranslationUnit(unit);
364 clang_disposeIndex(index);
365
366 return 0;
367}