+static CYUTF8String CYCXPoolUTF8Range(CYPool &pool, CXSourceRange range) {
+ CYCXPosition<> start(clang_getRangeStart(range));
+ CYCXPosition<> end(clang_getRangeEnd(range));
+ CYCXString file(start.file_);
+ _assert(file == CYCXString(end.file_));
+
+ CYPool temp;
+ size_t size;
+ char *data(static_cast<char *>(CYPoolFile(temp, file, &size)));
+ _assert(start.offset_ <= size && end.offset_ <= size && start.offset_ <= end.offset_);
+
+ CYUTF8String code;
+ code.size = end.offset_ - start.offset_;
+ code.data = pool.strndup(data + start.offset_, code.size);
+ return code;
+}
+
+static CYExpression *CYTranslateExpression(CXTranslationUnit unit, CXCursor cursor) {
+ switch (CXCursorKind kind = clang_getCursorKind(cursor)) {
+ case CXCursor_CallExpr: {
+ CYExpression *function(NULL);
+ CYList<CYArgument> arguments;
+ CYForChild(cursor, fun([&](CXCursor child) {
+ CYExpression *expression(CYTranslateExpression(unit, child));
+ if (function == NULL)
+ function = expression;
+ else
+ arguments->*$C_(expression);
+ }));
+ return $C(function, arguments);
+ } break;
+
+ case CXCursor_DeclRefExpr: {
+ return $V(CYCXString(cursor).Pool($pool));
+ } break;
+
+ case CXCursor_IntegerLiteral: {
+ // libclang doesn't provide any reasonable way to do this
+ // note: clang_tokenize doesn't work if this is a macro
+ // the token range starts inside the macro but ends after it
+ // the tokenizer freaks out and either fails with 0 tokens
+ // or returns some massive number of tokens ending here :/
+
+ CYUTF8String token(CYCXPoolUTF8Range($pool, clang_getCursorExtent(cursor)));
+ double value(CYCastDouble(token));
+ if (std::isnan(value))
+ return $V(token.data);
+ return $ CYNumber(value);
+ } break;
+
+ case CXCursor_CStyleCastExpr:
+ // XXX: most of the time, this is a "NoOp" integer cast; but we should check it
+
+ case CXCursor_UnexposedExpr:
+ // there is a very high probability that this is actually an "ImplicitCastExpr"
+ // "Douglas Gregor" <dgregor@apple.com> err'd on the incorrect side of this one
+ // http://lists.llvm.org/pipermail/cfe-commits/Week-of-Mon-20110926/046998.html
+
+ case CXCursor_ParenExpr: {
+ CYExpression *pass(NULL);
+ CYOneChild(cursor, fun([&](CXCursor child) {
+ pass = CYTranslateExpression(unit, child);
+ }));
+ return pass;
+ } break;
+
+ default:
+ //std::cerr << "E:" << CYCXString(kind) << std::endl;
+ _assert(false);
+ }
+}
+
+static CYStatement *CYTranslateStatement(CXTranslationUnit unit, CXCursor cursor) {
+ switch (CXCursorKind kind = clang_getCursorKind(cursor)) {
+ case CXCursor_ReturnStmt: {
+ CYExpression *value(NULL);
+ CYOneChild(cursor, fun([&](CXCursor child) {
+ value = CYTranslateExpression(unit, child);
+ }));
+ return $ CYReturn(value);
+ } break;
+
+ default:
+ //std::cerr << "S:" << CYCXString(kind) << std::endl;
+ _assert(false);
+ }
+}
+
+static CYStatement *CYTranslateBlock(CXTranslationUnit unit, CXCursor cursor) {
+ CYList<CYStatement> statements;
+ CYForChild(cursor, fun([&](CXCursor child) {
+ statements->*CYTranslateStatement(unit, child);
+ }));
+ return $ CYBlock(statements);
+}
+
+static CYType *CYDecodeType(CXType type);
+static void CYParseType(CXType type, CYType *typed);
+
+static void CYParseEnumeration(CXCursor cursor, CYType *typed) {
+ CYList<CYEnumConstant> constants;
+
+ CYForChild(cursor, fun([&](CXCursor child) {
+ if (clang_getCursorKind(child) == CXCursor_EnumConstantDecl)
+ constants->*$ CYEnumConstant($I($pool.strdup(CYCXString(child))), $D(clang_getEnumConstantDeclValue(child)));
+ }));
+
+ CYType *integer(CYDecodeType(clang_getEnumDeclIntegerType(cursor)));
+ typed->specifier_ = $ CYTypeEnum(NULL, integer->specifier_, constants);
+}
+
+static void CYParseStructure(CXCursor cursor, CYType *typed) {
+ CYList<CYTypeStructField> fields;
+ CYForChild(cursor, fun([&](CXCursor child) {
+ if (clang_getCursorKind(child) == CXCursor_FieldDecl)
+ fields->*$ CYTypeStructField(CYDecodeType(clang_getCursorType(child)), $I(CYCXString(child).Pool($pool)));
+ }));
+
+ typed->specifier_ = $ CYTypeStruct(NULL, $ CYStructTail(fields));
+}
+
+static void CYParseCursor(CXType type, CXCursor cursor, CYType *typed) {
+ CYCXString spelling(cursor);
+
+ switch (CXCursorKind kind = clang_getCursorKind(cursor)) {
+ case CXCursor_EnumDecl:
+ if (spelling[0] != '\0')
+ typed->specifier_ = $ CYTypeReference(CYTypeReferenceEnum, $I(spelling.Pool($pool)));
+ else
+ CYParseEnumeration(cursor, typed);
+ break;
+
+ case CXCursor_StructDecl: {
+ if (spelling[0] != '\0')
+ typed->specifier_ = $ CYTypeReference(CYTypeReferenceStruct, $I(spelling.Pool($pool)));
+ else
+ CYParseStructure(cursor, typed);
+ } break;
+
+ case CXCursor_UnionDecl: {
+ _assert(false);
+ } break;
+
+ default:
+ std::cerr << "C:" << CYCXString(kind) << std::endl;
+ _assert(false);
+ break;
+ }
+}
+
+static CYTypedParameter *CYParseSignature(CXType type, CYType *typed) {
+ CYParseType(clang_getResultType(type), typed);
+ CYList<CYTypedParameter> parameters;
+ for (int i(0), e(clang_getNumArgTypes(type)); i != e; ++i)
+ parameters->*$ CYTypedParameter(CYDecodeType(clang_getArgType(type, i)), NULL);
+ return parameters;
+}
+
+static void CYParseFunction(CXType type, CYType *typed) {
+ typed = typed->Modify($ CYTypeFunctionWith(clang_isFunctionTypeVariadic(type), CYParseSignature(type, typed)));
+}
+
+static void CYParseType(CXType type, CYType *typed) {
+ switch (CXTypeKind kind = type.kind) {
+ case CXType_Unexposed: {
+ CXType result(clang_getResultType(type));
+ if (result.kind == CXType_Invalid)
+ CYParseCursor(type, clang_getTypeDeclaration(type), typed);
+ else
+ // clang marks function pointers as Unexposed but still supports them
+ CYParseFunction(type, typed);
+ } break;
+
+ case CXType_Bool: typed->specifier_ = $ CYTypeVariable("bool"); break;
+ case CXType_WChar: typed->specifier_ = $ CYTypeVariable("wchar_t"); break;
+ case CXType_Float: typed->specifier_ = $ CYTypeFloating(0); break;
+ case CXType_Double: typed->specifier_ = $ CYTypeFloating(1); break;
+ case CXType_LongDouble: typed->specifier_ = $ CYTypeFloating(2); break;
+
+ case CXType_Char_U: typed->specifier_ = $ CYTypeCharacter(CYTypeNeutral); break;
+ case CXType_Char_S: typed->specifier_ = $ CYTypeCharacter(CYTypeNeutral); break;
+ case CXType_SChar: typed->specifier_ = $ CYTypeCharacter(CYTypeSigned); break;
+ case CXType_UChar: typed->specifier_ = $ CYTypeCharacter(CYTypeUnsigned); break;
+
+ case CXType_Short: typed->specifier_ = $ CYTypeIntegral(CYTypeSigned, 0); break;
+ case CXType_UShort: typed->specifier_ = $ CYTypeIntegral(CYTypeUnsigned, 0); break;
+
+ case CXType_Int: typed->specifier_ = $ CYTypeIntegral(CYTypeSigned, 1); break;
+ case CXType_UInt: typed->specifier_ = $ CYTypeIntegral(CYTypeUnsigned, 1); break;
+
+ case CXType_Long: typed->specifier_ = $ CYTypeIntegral(CYTypeSigned, 2); break;
+ case CXType_ULong: typed->specifier_ = $ CYTypeIntegral(CYTypeUnsigned, 2); break;
+
+ case CXType_LongLong: typed->specifier_ = $ CYTypeIntegral(CYTypeSigned, 3); break;
+ case CXType_ULongLong: typed->specifier_ = $ CYTypeIntegral(CYTypeUnsigned, 3); break;
+
+ case CXType_Int128: typed->specifier_ = $ CYTypeInt128(CYTypeSigned); break;
+ case CXType_UInt128: typed->specifier_ = $ CYTypeInt128(CYTypeUnsigned); break;
+
+ case CXType_BlockPointer: {
+ CXType pointee(clang_getPointeeType(type));
+ _assert(!clang_isFunctionTypeVariadic(pointee));
+ typed = typed->Modify($ CYTypeBlockWith(CYParseSignature(pointee, typed)));
+ } break;
+
+ case CXType_ConstantArray:
+ CYParseType(clang_getArrayElementType(type), typed);
+ typed = typed->Modify($ CYTypeArrayOf($D(clang_getArraySize(type))));
+ break;
+
+ case CXType_Enum:
+ typed->specifier_ = $ CYTypeVariable($pool.strdup(CYCXString(clang_getTypeSpelling(type))));
+ break;
+
+ case CXType_FunctionProto:
+ CYParseFunction(type, typed);
+ break;
+
+ case CXType_IncompleteArray:
+ // XXX: I probably should not decay to Pointer
+ CYParseType(clang_getArrayElementType(type), typed);
+ typed = typed->Modify($ CYTypePointerTo());
+ break;
+
+ case CXType_ObjCClass:
+ typed->specifier_ = $ CYTypeVariable("Class");
+ break;
+
+ case CXType_ObjCId:
+ typed->specifier_ = $ CYTypeVariable("id");
+ break;
+
+ case CXType_ObjCInterface:
+ typed->specifier_ = $ CYTypeVariable($pool.strdup(CYCXString(clang_getTypeSpelling(type))));
+ break;
+
+ case CXType_ObjCObjectPointer: {
+ CXType pointee(clang_getPointeeType(type));
+ if (pointee.kind != CXType_Unexposed) {
+ CYParseType(pointee, typed);
+ typed = typed->Modify($ CYTypePointerTo());
+ } else
+ // Clang seems to have internal typedefs for id and Class that are awkward
+ _assert(false);
+ } break;
+
+ case CXType_ObjCSel:
+ typed->specifier_ = $ CYTypeVariable("SEL");
+ break;
+
+ case CXType_Pointer:
+ CYParseType(clang_getPointeeType(type), typed);
+ typed = typed->Modify($ CYTypePointerTo());
+ break;
+
+ case CXType_Record:
+ typed->specifier_ = $ CYTypeReference(CYTypeReferenceStruct, $I($pool.strdup(CYCXString(clang_getTypeSpelling(type)))));
+ break;
+
+ case CXType_Typedef:
+ // use the declaration in order to isolate the name of the typedef itself
+ typed->specifier_ = $ CYTypeVariable($pool.strdup(CYCXString(clang_getTypeDeclaration(type))));
+ break;
+
+ case CXType_Vector:
+ _assert(false);
+ break;
+
+ case CXType_Void:
+ typed->specifier_ = $ CYTypeVoid();
+ break;
+
+ default:
+ std::cerr << "T:" << CYCXString(clang_getTypeKindSpelling(kind)) << std::endl;
+ std::cerr << "_: " << CYCXString(clang_getTypeSpelling(type)) << std::endl;
+ _assert(false);
+ }
+
+ if (clang_isConstQualifiedType(type))
+ typed = typed->Modify($ CYTypeConstant());
+}
+
+static CYType *CYDecodeType(CXType type) {
+ CYType *typed($ CYType(NULL));
+ CYParseType(type, typed);
+ return typed;
+}
+