1 /* Cycript - Optimizing JavaScript Compiler/Runtime
2 * Copyright (C) 2009-2015 Jay Freeman (saurik)
5 /* GNU Affero General Public License, Version 3 {{{ */
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.
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.
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/>.
28 #include <clang-c/Index.h>
30 #include "Functor.hpp"
31 #include "Replace.hpp"
34 static CXChildVisitResult
CYVisit(CXCursor cursor
, CXCursor parent
, CXClientData arg
) {
35 (*reinterpret_cast<const Functor
<void (CXCursor
)> *>(arg
))(cursor
);
36 return CXChildVisit_Continue
;
39 static unsigned CYForChild(CXCursor cursor
, const Functor
<void (CXCursor
)> &visitor
) {
40 return clang_visitChildren(cursor
, &CYVisit
, const_cast<void *>(static_cast<const void *>(&visitor
)));
43 static bool CYOneChild(CXCursor cursor
, const Functor
<void (CXCursor
)> &visitor
) {
45 CYForChild(cursor
, fun([&](CXCursor child
) {
56 CYCXString(CXString value
) :
61 CYCXString(CXCursor cursor
) :
62 value_(clang_getCursorSpelling(cursor
))
66 CYCXString(CXCursorKind kind
) :
67 value_(clang_getCursorKindSpelling(kind
))
71 CYCXString(CXTranslationUnit unit
, CXToken token
) :
72 value_(clang_getTokenSpelling(unit
, token
))
77 clang_disposeString(value_
);
80 operator const char *() const {
81 return clang_getCString(value_
);
84 const char *Pool(CYPool
&pool
) const {
85 return pool
.strdup(*this);
89 typedef std::map
<std::string
, std::string
> CYKeyMap
;
92 CXTranslationUnit unit
;
95 CYChildBaton(CXTranslationUnit unit
, CYKeyMap
&keys
) :
103 CXTranslationUnit unit
;
107 CYTokens(CXTranslationUnit unit
, CXCursor cursor
) :
110 CXSourceRange
range(clang_getCursorExtent(cursor
));
111 clang_tokenize(unit
, range
, &tokens
, &count
);
115 clang_disposeTokens(unit
, tokens
, count
);
118 operator CXToken
*() const {
123 static 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
;
133 arguments
->*$
C_(expression
);
135 return $
C(function
, arguments
);
138 case CXCursor_DeclRefExpr
: {
139 return $
V(CYCXString(cursor
).Pool($pool
));
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])));
149 case CXCursor_CStyleCastExpr
:
150 // XXX: most of the time, this is a "NoOp" integer cast; but we should check it
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
157 case CXCursor_ParenExpr
: {
158 CYExpression
*pass(NULL
);
159 CYOneChild(cursor
, fun([&](CXCursor child
) {
160 pass
= CYTranslateExpression(unit
, child
);
166 //std::cerr << "E:" << CYCXString(kind) << std::endl;
171 static 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
);
178 return $
CYReturn(value
);
182 //std::cerr << "S:" << CYCXString(kind) << std::endl;
187 static CYStatement
*CYTranslateBlock(CXTranslationUnit unit
, CXCursor cursor
) {
188 CYList
<CYStatement
> statements
;
189 CYForChild(cursor
, fun([&](CXCursor child
) {
190 statements
->*CYTranslateStatement(unit
, child
);
192 return $
CYBlock(statements
);
195 static CXChildVisitResult
CYChildVisit(CXCursor cursor
, CXCursor parent
, CXClientData arg
) {
196 CYChildBaton
&baton(*static_cast<CYChildBaton
*>(arg
));
197 CXTranslationUnit
&unit(baton
.unit
);
199 CYCXString
spelling(cursor
);
200 std::string
name(spelling
);
201 std::ostringstream value
;
203 /*CXSourceLocation location(clang_getCursorLocation(cursor));
209 clang_getSpellingLocation(location, &file, &line, &column, &offset);
212 CYCXString path(clang_getFileName(file));
213 std::cout << spelling << " " << path << ":" << line << std::endl;
216 switch (CXCursorKind kind
= clang_getCursorKind(cursor
)) {
217 case CXCursor_EnumConstantDecl
: {
218 value
<< clang_getEnumConstantDeclValue(cursor
);
221 case CXCursor_MacroDefinition
: {
222 CYTokens
tokens(unit
, cursor
);
223 if (tokens
.count
<= 2)
226 CXCursor cursors
[tokens
.count
];
227 clang_annotateTokens(unit
, tokens
, tokens
.count
, cursors
);
229 for (unsigned i(1); i
!= tokens
.count
- 1; ++i
) {
230 CYCXString
token(unit
, tokens
[i
]);
233 else if (strcmp(token
, "(") == 0)
239 case CXCursor_StructDecl
: {
240 if (!clang_isCursorDefinition(cursor
))
242 if (spelling
[0] == '\0')
245 std::ostringstream types
;
246 std::ostringstream names
;
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
) << "',";
257 value
<< "new Type([" << types
.str() << "],[" << names
.str() << "])";
260 case CXCursor_TypedefDecl
: {
261 CXType
type(clang_getTypedefDeclUnderlyingType(cursor
));
262 value
<< "(typedef " << CYCXString(clang_getTypeSpelling(type
)) << ")";
265 case CXCursor_FunctionDecl
:
266 case CXCursor_VarDecl
: try {
269 CYList
<CYFunctionParameter
> parameters
;
270 CYStatement
*code(NULL
);
274 CYForChild(cursor
, fun([&](CXCursor child
) {
275 switch (CXCursorKind kind
= clang_getCursorKind(child
)) {
276 case CXCursor_AsmLabelAttr
:
277 label
= CYCXString(child
);
280 case CXCursor_CompoundStmt
:
281 code
= CYTranslateBlock(unit
, child
);
284 case CXCursor_ParmDecl
:
285 parameters
->*$
P($
B($
I(CYCXString(child
).Pool($pool
))));
288 case CXCursor_IntegerLiteral
:
289 case CXCursor_ObjCClassRef
:
290 case CXCursor_TypeRef
:
291 case CXCursor_UnexposedAttr
:
295 std::cerr
<< "A:" << CYCXString(child
) << std::endl
;
303 } else if (label
[0] != '_')
307 CXType
type(clang_getCursorType(cursor
));
308 value
<< "*(typedef " << CYCXString(clang_getTypeSpelling(type
)) << ").pointerTo()(dlsym(RTLD_DEFAULT,'" << label
.substr(1) << "'))";
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;
316 } catch (const CYException
&error
) {
318 //std::cerr << error.PoolCString(pool) << std::endl;
323 return CXChildVisit_Recurse
;
327 baton
.keys
[name
] = value
.str();
330 return CXChildVisit_Continue
;
333 int main(int argc
, const char *argv
[]) {
334 CXIndex
index(clang_createIndex(0, 0));
336 const char *file(argv
[1]);
340 argv
[--offset
] = "-ObjC++";
343 CXTranslationUnit
unit(clang_parseTranslationUnit(index
, file
, argv
+ offset
, argc
- offset
, NULL
, 0, CXTranslationUnit_DetailedPreprocessingRecord
));
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
;
352 CYChildBaton
baton(unit
, keys
);
353 clang_visitChildren(clang_getTranslationUnitCursor(unit
), &CYChildVisit
, &baton
);
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')
360 std::cout
<< key
->first
<< "|\"" << value
<< "\"" << std::endl
;
363 clang_disposeTranslationUnit(unit
);
364 clang_disposeIndex(index
);