]> git.saurik.com Git - cycript.git/blame - Analyze.cpp
Require strings used as characters to be one byte.
[cycript.git] / Analyze.cpp
CommitLineData
7341eedb
JF
1/* Cycript - The Truly Universal Scripting Language
2 * Copyright (C) 2009-2016 Jay Freeman (saurik)
2e43a0b0
JF
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
3935b9e5 22#include <cmath>
8d20f0f1
JF
23#include <cstring>
24#include <iostream>
25#include <map>
26#include <sstream>
27#include <string>
28
29#include <clang-c/Index.h>
30
9d063d4a 31#include "Bridge.hpp"
2e43a0b0
JF
32#include "Functor.hpp"
33#include "Replace.hpp"
34#include "Syntax.hpp"
35
36static CXChildVisitResult CYVisit(CXCursor cursor, CXCursor parent, CXClientData arg) {
37 (*reinterpret_cast<const Functor<void (CXCursor)> *>(arg))(cursor);
38 return CXChildVisit_Continue;
39}
40
41static unsigned CYForChild(CXCursor cursor, const Functor<void (CXCursor)> &visitor) {
42 return clang_visitChildren(cursor, &CYVisit, const_cast<void *>(static_cast<const void *>(&visitor)));
43}
44
45static bool CYOneChild(CXCursor cursor, const Functor<void (CXCursor)> &visitor) {
46 bool visited(false);
47 CYForChild(cursor, fun([&](CXCursor child) {
48 _assert(!visited);
49 visited = true;
50 visitor(child);
51 }));
52 return visited;
53}
54
8d20f0f1
JF
55struct CYCXString {
56 CXString value_;
57
58 CYCXString(CXString value) :
59 value_(value)
60 {
61 }
62
2e43a0b0
JF
63 CYCXString(CXCursor cursor) :
64 value_(clang_getCursorSpelling(cursor))
65 {
66 }
67
68 CYCXString(CXCursorKind kind) :
69 value_(clang_getCursorKindSpelling(kind))
70 {
71 }
72
3935b9e5
JF
73 CYCXString(CXFile file) :
74 value_(clang_getFileName(file))
75 {
76 }
77
2e43a0b0
JF
78 CYCXString(CXTranslationUnit unit, CXToken token) :
79 value_(clang_getTokenSpelling(unit, token))
80 {
81 }
82
8d20f0f1
JF
83 ~CYCXString() {
84 clang_disposeString(value_);
85 }
86
87 operator const char *() const {
88 return clang_getCString(value_);
89 }
8d20f0f1 90
2e43a0b0
JF
91 const char *Pool(CYPool &pool) const {
92 return pool.strdup(*this);
8d20f0f1 93 }
7752205a
JF
94
95 bool operator ==(const char *rhs) const {
96 const char *lhs(*this);
97 return lhs == rhs || strcmp(lhs, rhs) == 0;
98 }
b7854baa
JF
99};
100
3935b9e5
JF
101template <void (&clang_get_Location)(CXSourceLocation, CXFile *, unsigned *, unsigned *, unsigned *) = clang_getSpellingLocation>
102struct CYCXPosition {
103 CXFile file_;
104 unsigned line_;
105 unsigned column_;
106 unsigned offset_;
107
108 CYCXPosition(CXSourceLocation location) {
109 clang_get_Location(location, &file_, &line_, &column_, &offset_);
110 }
111
7752205a
JF
112 CYCXPosition(CXTranslationUnit unit, CXToken token) :
113 CYCXPosition(clang_getTokenLocation(unit, token))
114 {
115 }
116
3935b9e5
JF
117 CXSourceLocation Get(CXTranslationUnit unit) const {
118 return clang_getLocation(unit, file_, line_, column_);
119 }
120};
121
122template <void (&clang_get_Location)(CXSourceLocation, CXFile *, unsigned *, unsigned *, unsigned *)>
123std::ostream &operator <<(std::ostream &out, const CYCXPosition<clang_get_Location> &position) {
124 if (position.file_ != NULL)
125 out << "[" << CYCXString(position.file_) << "]:";
7752205a
JF
126 out << position.line_ << ":" << position.column_ << "@" << position.offset_;
127 return out;
3935b9e5
JF
128}
129
83e1cbb8 130struct CYKey {
255fe37e
JF
131 unsigned priority_ = 0;
132
83e1cbb8
JF
133 std::string code_;
134 unsigned flags_;
135};
136
137typedef std::map<std::string, CYKey> CYKeyMap;
8d20f0f1
JF
138
139struct CYChildBaton {
140 CXTranslationUnit unit;
141 CYKeyMap &keys;
142
143 CYChildBaton(CXTranslationUnit unit, CYKeyMap &keys) :
144 unit(unit),
145 keys(keys)
146 {
147 }
148};
149
150struct CYTokens {
7752205a 151 private:
3935b9e5
JF
152 CXTranslationUnit unit_;
153 CXToken *tokens_;
154 unsigned count_;
7752205a 155 unsigned valid_;
3935b9e5 156
7752205a 157 public:
3935b9e5
JF
158 CYTokens(CXTranslationUnit unit, CXSourceRange range) :
159 unit_(unit)
160 {
161 clang_tokenize(unit_, range, &tokens_, &count_);
7752205a
JF
162
163
164 // libclang's tokenizer is horribly broken and returns "extra" tokens.
165 // this code goes back through the tokens and filters for good ones :/
166
167 CYCXPosition<> end(clang_getRangeEnd(range));
168 CYCXString file(end.file_);
169
170 for (valid_ = 0; valid_ != count_; ++valid_) {
171 CYCXPosition<> position(unit, tokens_[valid_]);
172 _assert(CYCXString(position.file_) == file);
173 if (position.offset_ >= end.offset_)
174 break;
175 }
3935b9e5 176 }
8d20f0f1
JF
177
178 CYTokens(CXTranslationUnit unit, CXCursor cursor) :
3935b9e5 179 CYTokens(unit, clang_getCursorExtent(cursor))
8d20f0f1 180 {
8d20f0f1
JF
181 }
182
183 ~CYTokens() {
3935b9e5 184 clang_disposeTokens(unit_, tokens_, count_);
8d20f0f1
JF
185 }
186
187 operator CXToken *() const {
3935b9e5 188 return tokens_;
8d20f0f1 189 }
7752205a
JF
190
191 size_t size() const {
192 return valid_;
193 }
8d20f0f1
JF
194};
195
38c824bf
JF
196static CYUTF8String CYCXPoolUTF8Range(CYPool &pool, CXSourceRange range) {
197 CYCXPosition<> start(clang_getRangeStart(range));
198 CYCXPosition<> end(clang_getRangeEnd(range));
199 CYCXString file(start.file_);
200 _assert(file == CYCXString(end.file_));
201
202 CYPool temp;
203 size_t size;
204 char *data(static_cast<char *>(CYPoolFile(temp, file, &size)));
205 _assert(start.offset_ <= size && end.offset_ <= size && start.offset_ <= end.offset_);
206
207 CYUTF8String code;
208 code.size = end.offset_ - start.offset_;
209 code.data = pool.strndup(data + start.offset_, code.size);
210 return code;
211}
212
2e43a0b0
JF
213static CYExpression *CYTranslateExpression(CXTranslationUnit unit, CXCursor cursor) {
214 switch (CXCursorKind kind = clang_getCursorKind(cursor)) {
215 case CXCursor_CallExpr: {
216 CYExpression *function(NULL);
217 CYList<CYArgument> arguments;
218 CYForChild(cursor, fun([&](CXCursor child) {
219 CYExpression *expression(CYTranslateExpression(unit, child));
220 if (function == NULL)
221 function = expression;
222 else
223 arguments->*$C_(expression);
224 }));
225 return $C(function, arguments);
226 } break;
227
228 case CXCursor_DeclRefExpr: {
229 return $V(CYCXString(cursor).Pool($pool));
230 } break;
231
232 case CXCursor_IntegerLiteral: {
3935b9e5
JF
233 // libclang doesn't provide any reasonable way to do this
234 // note: clang_tokenize doesn't work if this is a macro
235 // the token range starts inside the macro but ends after it
236 // the tokenizer freaks out and either fails with 0 tokens
237 // or returns some massive number of tokens ending here :/
238
38c824bf 239 CYUTF8String token(CYCXPoolUTF8Range($pool, clang_getCursorExtent(cursor)));
3935b9e5 240 double value(CYCastDouble(token));
38c824bf
JF
241 if (std::isnan(value))
242 return $V(token.data);
243 return $ CYNumber(value);
2e43a0b0
JF
244 } break;
245
246 case CXCursor_CStyleCastExpr:
247 // XXX: most of the time, this is a "NoOp" integer cast; but we should check it
248
249 case CXCursor_UnexposedExpr:
250 // there is a very high probability that this is actually an "ImplicitCastExpr"
251 // "Douglas Gregor" <dgregor@apple.com> err'd on the incorrect side of this one
252 // http://lists.llvm.org/pipermail/cfe-commits/Week-of-Mon-20110926/046998.html
253
254 case CXCursor_ParenExpr: {
255 CYExpression *pass(NULL);
256 CYOneChild(cursor, fun([&](CXCursor child) {
257 pass = CYTranslateExpression(unit, child);
258 }));
259 return pass;
260 } break;
261
262 default:
263 //std::cerr << "E:" << CYCXString(kind) << std::endl;
264 _assert(false);
265 }
266}
267
268static CYStatement *CYTranslateStatement(CXTranslationUnit unit, CXCursor cursor) {
269 switch (CXCursorKind kind = clang_getCursorKind(cursor)) {
270 case CXCursor_ReturnStmt: {
271 CYExpression *value(NULL);
272 CYOneChild(cursor, fun([&](CXCursor child) {
273 value = CYTranslateExpression(unit, child);
274 }));
275 return $ CYReturn(value);
276 } break;
277
278 default:
279 //std::cerr << "S:" << CYCXString(kind) << std::endl;
280 _assert(false);
281 }
282}
283
284static CYStatement *CYTranslateBlock(CXTranslationUnit unit, CXCursor cursor) {
285 CYList<CYStatement> statements;
286 CYForChild(cursor, fun([&](CXCursor child) {
287 statements->*CYTranslateStatement(unit, child);
288 }));
289 return $ CYBlock(statements);
290}
291
5b4dabb2
JF
292static CYType *CYDecodeType(CXType type);
293static void CYParseType(CXType type, CYType *typed);
d9241e23 294
5b4dabb2 295static void CYParseEnumeration(CXCursor cursor, CYType *typed) {
aaa29c28
JF
296 CYList<CYEnumConstant> constants;
297
298 CYForChild(cursor, fun([&](CXCursor child) {
299 if (clang_getCursorKind(child) == CXCursor_EnumConstantDecl)
300 constants->*$ CYEnumConstant($I($pool.strdup(CYCXString(child))), $D(clang_getEnumConstantDeclValue(child)));
301 }));
302
5b4dabb2 303 CYType *integer(CYDecodeType(clang_getEnumDeclIntegerType(cursor)));
aaa29c28
JF
304 typed->specifier_ = $ CYTypeEnum(NULL, integer->specifier_, constants);
305}
306
5b4dabb2 307static void CYParseStructure(CXCursor cursor, CYType *typed) {
b0e6429c
JF
308 CYList<CYTypeStructField> fields;
309 CYForChild(cursor, fun([&](CXCursor child) {
5b4dabb2
JF
310 if (clang_getCursorKind(child) == CXCursor_FieldDecl)
311 fields->*$ CYTypeStructField(CYDecodeType(clang_getCursorType(child)), $I(CYCXString(child).Pool($pool)));
b0e6429c
JF
312 }));
313
314 typed->specifier_ = $ CYTypeStruct(NULL, $ CYStructTail(fields));
315}
316
5b4dabb2 317static void CYParseCursor(CXType type, CXCursor cursor, CYType *typed) {
d9241e23
JF
318 CYCXString spelling(cursor);
319
320 switch (CXCursorKind kind = clang_getCursorKind(cursor)) {
321 case CXCursor_EnumDecl:
322 if (spelling[0] != '\0')
aaa29c28 323 typed->specifier_ = $ CYTypeReference(CYTypeReferenceEnum, $I(spelling.Pool($pool)));
d9241e23 324 else
aaa29c28 325 CYParseEnumeration(cursor, typed);
d9241e23
JF
326 break;
327
328 case CXCursor_StructDecl: {
329 if (spelling[0] != '\0')
aaa29c28 330 typed->specifier_ = $ CYTypeReference(CYTypeReferenceStruct, $I(spelling.Pool($pool)));
b0e6429c
JF
331 else
332 CYParseStructure(cursor, typed);
d9241e23
JF
333 } break;
334
335 case CXCursor_UnionDecl: {
336 _assert(false);
337 } break;
338
339 default:
340 std::cerr << "C:" << CYCXString(kind) << std::endl;
341 _assert(false);
342 break;
343 }
344}
345
5b4dabb2 346static CYTypedParameter *CYParseSignature(CXType type, CYType *typed) {
d9241e23
JF
347 CYParseType(clang_getResultType(type), typed);
348 CYList<CYTypedParameter> parameters;
349 for (int i(0), e(clang_getNumArgTypes(type)); i != e; ++i)
5b4dabb2 350 parameters->*$ CYTypedParameter(CYDecodeType(clang_getArgType(type, i)), NULL);
d9241e23
JF
351 return parameters;
352}
353
5b4dabb2 354static void CYParseFunction(CXType type, CYType *typed) {
d9241e23
JF
355 typed = typed->Modify($ CYTypeFunctionWith(clang_isFunctionTypeVariadic(type), CYParseSignature(type, typed)));
356}
357
5b4dabb2 358static void CYParseType(CXType type, CYType *typed) {
d9241e23
JF
359 switch (CXTypeKind kind = type.kind) {
360 case CXType_Unexposed: {
361 CXType result(clang_getResultType(type));
362 if (result.kind == CXType_Invalid)
363 CYParseCursor(type, clang_getTypeDeclaration(type), typed);
364 else
365 // clang marks function pointers as Unexposed but still supports them
366 CYParseFunction(type, typed);
367 } break;
368
369 case CXType_Bool: typed->specifier_ = $ CYTypeVariable("bool"); break;
1e8d8047
JF
370 case CXType_WChar: typed->specifier_ = $ CYTypeVariable("wchar_t"); break;
371 case CXType_Float: typed->specifier_ = $ CYTypeFloating(0); break;
372 case CXType_Double: typed->specifier_ = $ CYTypeFloating(1); break;
373 case CXType_LongDouble: typed->specifier_ = $ CYTypeFloating(2); break;
d9241e23
JF
374
375 case CXType_Char_U: typed->specifier_ = $ CYTypeCharacter(CYTypeNeutral); break;
376 case CXType_Char_S: typed->specifier_ = $ CYTypeCharacter(CYTypeNeutral); break;
377 case CXType_SChar: typed->specifier_ = $ CYTypeCharacter(CYTypeSigned); break;
378 case CXType_UChar: typed->specifier_ = $ CYTypeCharacter(CYTypeUnsigned); break;
379
380 case CXType_Short: typed->specifier_ = $ CYTypeIntegral(CYTypeSigned, 0); break;
381 case CXType_UShort: typed->specifier_ = $ CYTypeIntegral(CYTypeUnsigned, 0); break;
382
383 case CXType_Int: typed->specifier_ = $ CYTypeIntegral(CYTypeSigned, 1); break;
384 case CXType_UInt: typed->specifier_ = $ CYTypeIntegral(CYTypeUnsigned, 1); break;
385
386 case CXType_Long: typed->specifier_ = $ CYTypeIntegral(CYTypeSigned, 2); break;
387 case CXType_ULong: typed->specifier_ = $ CYTypeIntegral(CYTypeUnsigned, 2); break;
388
389 case CXType_LongLong: typed->specifier_ = $ CYTypeIntegral(CYTypeSigned, 3); break;
390 case CXType_ULongLong: typed->specifier_ = $ CYTypeIntegral(CYTypeUnsigned, 3); break;
391
24ffc58c
JF
392 case CXType_Int128: typed->specifier_ = $ CYTypeInt128(CYTypeSigned); break;
393 case CXType_UInt128: typed->specifier_ = $ CYTypeInt128(CYTypeUnsigned); break;
394
d9241e23
JF
395 case CXType_BlockPointer: {
396 CXType pointee(clang_getPointeeType(type));
397 _assert(!clang_isFunctionTypeVariadic(pointee));
398 typed = typed->Modify($ CYTypeBlockWith(CYParseSignature(pointee, typed)));
399 } break;
400
401 case CXType_ConstantArray:
402 CYParseType(clang_getArrayElementType(type), typed);
403 typed = typed->Modify($ CYTypeArrayOf($D(clang_getArraySize(type))));
404 break;
405
406 case CXType_Enum:
407 typed->specifier_ = $ CYTypeVariable($pool.strdup(CYCXString(clang_getTypeSpelling(type))));
408 break;
409
410 case CXType_FunctionProto:
411 CYParseFunction(type, typed);
412 break;
413
414 case CXType_IncompleteArray:
aaa29c28
JF
415 // XXX: I probably should not decay to Pointer
416 CYParseType(clang_getArrayElementType(type), typed);
417 typed = typed->Modify($ CYTypePointerTo());
d9241e23
JF
418 break;
419
b0e6429c
JF
420 case CXType_ObjCClass:
421 typed->specifier_ = $ CYTypeVariable("Class");
422 break;
423
d9241e23
JF
424 case CXType_ObjCId:
425 typed->specifier_ = $ CYTypeVariable("id");
426 break;
427
428 case CXType_ObjCInterface:
429 typed->specifier_ = $ CYTypeVariable($pool.strdup(CYCXString(clang_getTypeSpelling(type))));
430 break;
431
432 case CXType_ObjCObjectPointer: {
433 CXType pointee(clang_getPointeeType(type));
434 if (pointee.kind != CXType_Unexposed) {
435 CYParseType(pointee, typed);
436 typed = typed->Modify($ CYTypePointerTo());
437 } else
438 // Clang seems to have internal typedefs for id and Class that are awkward
439 _assert(false);
440 } break;
441
442 case CXType_ObjCSel:
443 typed->specifier_ = $ CYTypeVariable("SEL");
444 break;
445
446 case CXType_Pointer:
447 CYParseType(clang_getPointeeType(type), typed);
448 typed = typed->Modify($ CYTypePointerTo());
449 break;
450
451 case CXType_Record:
aaa29c28 452 typed->specifier_ = $ CYTypeReference(CYTypeReferenceStruct, $I($pool.strdup(CYCXString(clang_getTypeSpelling(type)))));
d9241e23
JF
453 break;
454
455 case CXType_Typedef:
456 // use the declaration in order to isolate the name of the typedef itself
457 typed->specifier_ = $ CYTypeVariable($pool.strdup(CYCXString(clang_getTypeDeclaration(type))));
458 break;
459
460 case CXType_Vector:
461 _assert(false);
462 break;
463
464 case CXType_Void:
465 typed->specifier_ = $ CYTypeVoid();
466 break;
467
468 default:
469 std::cerr << "T:" << CYCXString(clang_getTypeKindSpelling(kind)) << std::endl;
470 std::cerr << "_: " << CYCXString(clang_getTypeSpelling(type)) << std::endl;
471 _assert(false);
472 }
473
474 if (clang_isConstQualifiedType(type))
475 typed = typed->Modify($ CYTypeConstant());
476}
477
5b4dabb2
JF
478static CYType *CYDecodeType(CXType type) {
479 CYType *typed($ CYType(NULL));
d9241e23
JF
480 CYParseType(type, typed);
481 return typed;
482}
483
8d20f0f1
JF
484static CXChildVisitResult CYChildVisit(CXCursor cursor, CXCursor parent, CXClientData arg) {
485 CYChildBaton &baton(*static_cast<CYChildBaton *>(arg));
486 CXTranslationUnit &unit(baton.unit);
487
aaa29c28 488 CXChildVisitResult result(CXChildVisit_Continue);
2e43a0b0 489 CYCXString spelling(cursor);
8d20f0f1
JF
490 std::string name(spelling);
491 std::ostringstream value;
255fe37e 492 unsigned priority(2);
9d063d4a 493 unsigned flags(CYBridgeHold);
8d20f0f1
JF
494
495 /*CXSourceLocation location(clang_getCursorLocation(cursor));
3935b9e5 496 CYCXPosition<> position(location);
d9241e23 497 std::cerr << spelling << " " << position << std::endl;*/
8d20f0f1 498
b0e6429c 499 try { switch (CXCursorKind kind = clang_getCursorKind(cursor)) {
8d20f0f1
JF
500 case CXCursor_EnumConstantDecl: {
501 value << clang_getEnumConstantDeclValue(cursor);
502 } break;
503
aaa29c28
JF
504 case CXCursor_EnumDecl: {
505 if (spelling[0] == '\0')
506 goto skip;
507 // XXX: this was blindly copied from StructDecl
508 if (!clang_isCursorDefinition(cursor))
509 priority = 1;
510
511 CYLocalPool pool;
512
5b4dabb2 513 CYType typed;
aaa29c28
JF
514 CYParseEnumeration(cursor, &typed);
515
516 CYOptions options;
517 CYOutput out(*value.rdbuf(), options);
518 CYTypeExpression(&typed).Output(out, CYNoBFC);
519
520 value << ".withName(\"" << name << "\")";
84096608 521 name = "$cye" + name;
aaa29c28
JF
522 flags = CYBridgeType;
523
524 // the enum constants are implemented separately *also*
525 // XXX: maybe move output logic to function we can call
526 result = CXChildVisit_Recurse;
527 } break;
528
b0e6429c 529 case CXCursor_MacroDefinition: {
7752205a
JF
530 CXSourceRange range(clang_getCursorExtent(cursor));
531 CYTokens tokens(unit, range);
532 _assert(tokens.size() != 0);
8d20f0f1 533
7752205a
JF
534 CXCursor cursors[tokens.size()];
535 clang_annotateTokens(unit, tokens, tokens.size(), cursors);
8d20f0f1 536
dee38f6c
JF
537 CYLocalPool local;
538 CYList<CYFunctionParameter> parameters;
539 unsigned offset(1);
540
541 if (tokens.size() != 1) {
542 CYCXPosition<> start(clang_getRangeStart(range));
543 CYCXString first(unit, tokens[offset]);
544 if (first == "(") {
545 CYCXPosition<> paren(unit, tokens[offset]);
546 if (start.offset_ + strlen(spelling) == paren.offset_) {
547 for (;;) {
548 _assert(++offset != tokens.size());
549 CYCXString token(unit, tokens[offset]);
550 parameters->*$P($B($I(token.Pool($pool))));
551 _assert(++offset != tokens.size());
552 CYCXString comma(unit, tokens[offset]);
553 if (comma == ")")
554 break;
555 _assert(comma == ",");
556 }
557 ++offset;
558 }
559 }
7752205a
JF
560 }
561
dee38f6c
JF
562 std::ostringstream body;
563 for (unsigned i(offset); i != tokens.size(); ++i) {
2e43a0b0 564 CYCXString token(unit, tokens[i]);
dee38f6c
JF
565 if (i != offset)
566 body << " ";
567 body << token;
568 }
569
570 if (!parameters)
571 value << body.str();
572 else {
573 CYOptions options;
574 CYOutput out(*value.rdbuf(), options);
575 out << '(' << "function" << '(';
576 out << parameters;
577 out << ')' << '{';
578 out << "return" << ' ';
579 value << body.str();
580 out << ';' << '}' << ')';
8d20f0f1
JF
581 }
582 } break;
583
584 case CXCursor_StructDecl: {
8d20f0f1
JF
585 if (spelling[0] == '\0')
586 goto skip;
255fe37e
JF
587 if (!clang_isCursorDefinition(cursor))
588 priority = 1;
8d20f0f1 589
b0e6429c 590 CYLocalPool pool;
2e43a0b0 591
5b4dabb2 592 CYType typed;
b0e6429c
JF
593 CYParseStructure(cursor, &typed);
594
595 CYOptions options;
596 CYOutput out(*value.rdbuf(), options);
597 CYTypeExpression(&typed).Output(out, CYNoBFC);
8d20f0f1 598
b0e6429c 599 value << ".withName(\"" << name << "\")";
84096608 600 name = "$cys" + name;
9d063d4a 601 flags = CYBridgeType;
8d20f0f1
JF
602 } break;
603
b0e6429c 604 case CXCursor_TypedefDecl: {
d9241e23
JF
605 CYLocalPool local;
606
5b4dabb2 607 CYType *typed(CYDecodeType(clang_getTypedefDeclUnderlyingType(cursor)));
d9241e23
JF
608 if (typed->specifier_ == NULL)
609 value << "(typedef " << CYCXString(clang_getTypeSpelling(clang_getTypedefDeclUnderlyingType(cursor))) << ")";
610 else {
611 CYOptions options;
612 CYOutput out(*value.rdbuf(), options);
613 CYTypeExpression(typed).Output(out, CYNoBFC);
614 }
8d20f0f1
JF
615 } break;
616
617 case CXCursor_FunctionDecl:
b0e6429c 618 case CXCursor_VarDecl: {
2e43a0b0
JF
619 std::string label;
620
621 CYList<CYFunctionParameter> parameters;
622 CYStatement *code(NULL);
623
624 CYLocalPool local;
625
626 CYForChild(cursor, fun([&](CXCursor child) {
627 switch (CXCursorKind kind = clang_getCursorKind(child)) {
628 case CXCursor_AsmLabelAttr:
629 label = CYCXString(child);
630 break;
631
632 case CXCursor_CompoundStmt:
633 code = CYTranslateBlock(unit, child);
634 break;
635
636 case CXCursor_ParmDecl:
637 parameters->*$P($B($I(CYCXString(child).Pool($pool))));
638 break;
639
640 case CXCursor_IntegerLiteral:
641 case CXCursor_ObjCClassRef:
642 case CXCursor_TypeRef:
643 case CXCursor_UnexposedAttr:
644 break;
645
646 default:
3935b9e5 647 //std::cerr << "A:" << CYCXString(child) << std::endl;
2e43a0b0
JF
648 break;
649 }
650 }));
651
652 if (label.empty()) {
653 label = spelling;
654 label = '_' + label;
655 } else if (label[0] != '_')
b7854baa
JF
656 goto skip;
657
2e43a0b0 658 if (code == NULL) {
1e8d8047 659 value << "*";
2e43a0b0 660 CXType type(clang_getCursorType(cursor));
1e8d8047
JF
661 CYType *typed(CYDecodeType(type));
662 CYOptions options;
663 CYOutput out(*value.rdbuf(), options);
664 CYTypeExpression(typed).Output(out, CYNoBFC);
665 value << ".pointerTo()(dlsym(RTLD_DEFAULT,'" << label.substr(1) << "'))";
2e43a0b0
JF
666 } else {
667 CYOptions options;
668 CYOutput out(*value.rdbuf(), options);
669 CYFunctionExpression *function($ CYFunctionExpression(NULL, parameters, code));
670 function->Output(out, CYNoBFC);
671 //std::cerr << value.str() << std::endl;
672 }
8d20f0f1
JF
673 } break;
674
aaa29c28
JF
675 default:
676 result = CXChildVisit_Recurse;
677 goto skip;
678 break;
b0e6429c 679 } {
83e1cbb8 680 CYKey &key(baton.keys[name]);
dc4fc6be 681 if (key.priority_ <= priority) {
255fe37e
JF
682 key.priority_ = priority;
683 key.code_ = value.str();
684 key.flags_ = flags;
685 }
b0e6429c
JF
686 } } catch (const CYException &error) {
687 CYPool pool;
688 //std::cerr << error.PoolCString(pool) << std::endl;
83e1cbb8 689 }
8d20f0f1
JF
690
691 skip:
aaa29c28 692 return result;
8d20f0f1
JF
693}
694
695int main(int argc, const char *argv[]) {
696 CXIndex index(clang_createIndex(0, 0));
697
698 const char *file(argv[1]);
699
700 unsigned offset(3);
701#if CY_OBJECTIVEC
702 argv[--offset] = "-ObjC++";
703#endif
704
2e43a0b0 705 CXTranslationUnit unit(clang_parseTranslationUnit(index, file, argv + offset, argc - offset, NULL, 0, CXTranslationUnit_DetailedPreprocessingRecord));
8d20f0f1
JF
706
707 for (unsigned i(0), e(clang_getNumDiagnostics(unit)); i != e; ++i) {
708 CXDiagnostic diagnostic(clang_getDiagnostic(unit, i));
709 CYCXString spelling(clang_getDiagnosticSpelling(diagnostic));
710 std::cerr << spelling << std::endl;
711 }
712
713 CYKeyMap keys;
714 CYChildBaton baton(unit, keys);
715 clang_visitChildren(clang_getTranslationUnitCursor(unit), &CYChildVisit, &baton);
716
717 for (CYKeyMap::const_iterator key(keys.begin()); key != keys.end(); ++key) {
83e1cbb8
JF
718 std::string code(key->second.code_);
719 for (size_t i(0), e(code.size()); i != e; ++i)
720 if (code[i] <= 0 || code[i] >= 0x7f || code[i] == '\n')
8d20f0f1 721 goto skip;
83e1cbb8 722 std::cout << key->first << "|" << key->second.flags_ << "\"" << code << "\"" << std::endl;
8d20f0f1
JF
723 skip:; }
724
725 clang_disposeTranslationUnit(unit);
726 clang_disposeIndex(index);
727
728 return 0;
729}