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