]> git.saurik.com Git - cycript.git/blobdiff - Analyze.cpp
Allow the size of array typedefs to be a variable.
[cycript.git] / Analyze.cpp
index 466144d1fac5fbcafbc9875a7a41f901ce87df57..5bf49148fcb0c6f4504fe95483c1f078a3144c15 100644 (file)
@@ -28,6 +28,7 @@
 
 #include <clang-c/Index.h>
 
+#include "Bridge.hpp"
 #include "Functor.hpp"
 #include "Replace.hpp"
 #include "Syntax.hpp"
@@ -288,42 +289,47 @@ static CYStatement *CYTranslateBlock(CXTranslationUnit unit, CXCursor cursor) {
     return $ CYBlock(statements);
 }
 
-static CYTypedIdentifier *CYDecodeType(CXType type);
-static void CYParseType(CXType type, CYTypedIdentifier *typed);
+static CYType *CYDecodeType(CXType type);
+static void CYParseType(CXType type, CYType *typed);
 
-static CYTypedIdentifier *CYDecodeType(CXType type, const CYCXString &identifier) {
-    CYTypedIdentifier *typed(CYDecodeType(type));
-    typed->identifier_ = $ CYIdentifier(identifier.Pool($pool));
-    return 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 CYParseCursor(CXType type, CXCursor cursor, CYTypedIdentifier *typed) {
+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')
-                // XXX: should we have a special enum keyword?
-                typed->specifier_ = $ CYTypeVariable($I(spelling.Pool($pool)));
+                typed->specifier_ = $ CYTypeReference(CYTypeReferenceEnum, $I(spelling.Pool($pool)));
             else
-                // XXX: maybe replace with "enum : int" instead of "int"
-                CYParseType(clang_getEnumDeclIntegerType(cursor), typed);
+                CYParseEnumeration(cursor, typed);
         break;
 
         case CXCursor_StructDecl: {
             if (spelling[0] != '\0')
-                typed->specifier_ = $ CYTypeReference($I(spelling.Pool($pool)));
-            else {
-                CYList<CYTypeStructField> fields;
-                CYForChild(cursor, fun([&](CXCursor child) {
-                    if (clang_getCursorKind(child) == CXCursor_FieldDecl) {
-                        CYTypedIdentifier *field(CYDecodeType(clang_getCursorType(child), child));
-                        fields->*$ CYTypeStructField(field);
-                    }
-                }));
-
-                typed->specifier_ = $ CYTypeStruct(NULL, $ CYStructTail(fields));
-            }
+                typed->specifier_ = $ CYTypeReference(CYTypeReferenceStruct, $I(spelling.Pool($pool)));
+            else
+                CYParseStructure(cursor, typed);
         } break;
 
         case CXCursor_UnionDecl: {
@@ -337,19 +343,19 @@ static void CYParseCursor(CXType type, CXCursor cursor, CYTypedIdentifier *typed
     }
 }
 
-static CYTypedParameter *CYParseSignature(CXType type, CYTypedIdentifier *typed) {
+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)));
+        parameters->*$ CYTypedParameter(CYDecodeType(clang_getArgType(type, i)), NULL);
     return parameters;
 }
 
-static void CYParseFunction(CXType type, CYTypedIdentifier *typed) {
+static void CYParseFunction(CXType type, CYType *typed) {
     typed = typed->Modify($ CYTypeFunctionWith(clang_isFunctionTypeVariadic(type), CYParseSignature(type, typed)));
 }
 
-static void CYParseType(CXType type, CYTypedIdentifier *typed) {
+static void CYParseType(CXType type, CYType *typed) {
     switch (CXTypeKind kind = type.kind) {
         case CXType_Unexposed: {
             CXType result(clang_getResultType(type));
@@ -361,8 +367,10 @@ static void CYParseType(CXType type, CYTypedIdentifier *typed) {
         } break;
 
         case CXType_Bool: typed->specifier_ = $ CYTypeVariable("bool"); break;
-        case CXType_Float: typed->specifier_ = $ CYTypeVariable("float"); break;
-        case CXType_Double: typed->specifier_ = $ CYTypeVariable("double"); 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;
@@ -404,8 +412,13 @@ static void CYParseType(CXType type, CYTypedIdentifier *typed) {
         break;
 
         case CXType_IncompleteArray:
-            // XXX: I should support these :/
-            _assert(false);
+            // 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:
@@ -436,7 +449,7 @@ static void CYParseType(CXType type, CYTypedIdentifier *typed) {
         break;
 
         case CXType_Record:
-            typed->specifier_ = $ CYTypeReference($I($pool.strdup(CYCXString(clang_getTypeSpelling(type)))));
+            typed->specifier_ = $ CYTypeReference(CYTypeReferenceStruct, $I($pool.strdup(CYCXString(clang_getTypeSpelling(type)))));
         break;
 
         case CXType_Typedef:
@@ -462,8 +475,8 @@ static void CYParseType(CXType type, CYTypedIdentifier *typed) {
         typed = typed->Modify($ CYTypeConstant());
 }
 
-static CYTypedIdentifier *CYDecodeType(CXType type) {
-    CYTypedIdentifier *typed($ CYTypedIdentifier(NULL));
+static CYType *CYDecodeType(CXType type) {
+    CYType *typed($ CYType(NULL));
     CYParseType(type, typed);
     return typed;
 }
@@ -472,22 +485,48 @@ static CXChildVisitResult CYChildVisit(CXCursor cursor, CXCursor parent, CXClien
     CYChildBaton &baton(*static_cast<CYChildBaton *>(arg));
     CXTranslationUnit &unit(baton.unit);
 
+    CXChildVisitResult result(CXChildVisit_Continue);
     CYCXString spelling(cursor);
     std::string name(spelling);
     std::ostringstream value;
     unsigned priority(2);
-    unsigned flags(0);
+    unsigned flags(CYBridgeHold);
 
     /*CXSourceLocation location(clang_getCursorLocation(cursor));
     CYCXPosition<> position(location);
     std::cerr << spelling << " " << position << std::endl;*/
 
-    switch (CXCursorKind kind = clang_getCursorKind(cursor)) {
+    try { switch (CXCursorKind kind = clang_getCursorKind(cursor)) {
         case CXCursor_EnumConstantDecl: {
             value << clang_getEnumConstantDeclValue(cursor);
         } break;
 
-        case CXCursor_MacroDefinition: try {
+        case CXCursor_EnumDecl: {
+            if (spelling[0] == '\0')
+                goto skip;
+            // XXX: this was blindly copied from StructDecl
+            if (!clang_isCursorDefinition(cursor))
+                priority = 1;
+
+            CYLocalPool pool;
+
+            CYType typed;
+            CYParseEnumeration(cursor, &typed);
+
+            CYOptions options;
+            CYOutput out(*value.rdbuf(), options);
+            CYTypeExpression(&typed).Output(out, CYNoBFC);
+
+            value << ".withName(\"" << name << "\")";
+            name = "$cye" + name;
+            flags = CYBridgeType;
+
+            // the enum constants are implemented separately *also*
+            // XXX: maybe move output logic to function we can call
+            result = CXChildVisit_Recurse;
+        } break;
+
+        case CXCursor_MacroDefinition: {
             CXSourceRange range(clang_getCursorExtent(cursor));
             CYTokens tokens(unit, range);
             _assert(tokens.size() != 0);
@@ -540,10 +579,6 @@ static CXChildVisitResult CYChildVisit(CXCursor cursor, CXCursor parent, CXClien
                 value << body.str();
                 out << ';' << '}' << ')';
             }
-        } catch (const CYException &error) {
-            CYPool pool;
-            //std::cerr << error.PoolCString(pool) << std::endl;
-            goto skip;
         } break;
 
         case CXCursor_StructDecl: {
@@ -552,25 +587,24 @@ static CXChildVisitResult CYChildVisit(CXCursor cursor, CXCursor parent, CXClien
             if (!clang_isCursorDefinition(cursor))
                 priority = 1;
 
-            std::ostringstream types;
-            std::ostringstream names;
+            CYLocalPool pool;
 
-            CYForChild(cursor, fun([&](CXCursor child) {
-                if (clang_getCursorKind(child) == CXCursor_FieldDecl) {
-                    CXType type(clang_getCursorType(child));
-                    types << "(typedef " << CYCXString(clang_getTypeSpelling(type)) << "),";
-                    names << "'" << CYCXString(child) << "',";
-                }
-            }));
+            CYType typed;
+            CYParseStructure(cursor, &typed);
+
+            CYOptions options;
+            CYOutput out(*value.rdbuf(), options);
+            CYTypeExpression(&typed).Output(out, CYNoBFC);
 
-            value << "new Type([" << types.str() << "],[" << names.str() << "]).withName(\"" << name << "\")";
-            name += "$cy";
+            value << ".withName(\"" << name << "\")";
+            name = "$cys" + name;
+            flags = CYBridgeType;
         } break;
 
-        case CXCursor_TypedefDecl: try {
+        case CXCursor_TypedefDecl: {
             CYLocalPool local;
 
-            CYTypedIdentifier *typed(CYDecodeType(clang_getTypedefDeclUnderlyingType(cursor)));
+            CYType *typed(CYDecodeType(clang_getTypedefDeclUnderlyingType(cursor)));
             if (typed->specifier_ == NULL)
                 value << "(typedef " << CYCXString(clang_getTypeSpelling(clang_getTypedefDeclUnderlyingType(cursor))) << ")";
             else {
@@ -578,14 +612,10 @@ static CXChildVisitResult CYChildVisit(CXCursor cursor, CXCursor parent, CXClien
                 CYOutput out(*value.rdbuf(), options);
                 CYTypeExpression(typed).Output(out, CYNoBFC);
             }
-        } catch (const CYException &error) {
-            CYPool pool;
-            //std::cerr << error.PoolCString(pool) << std::endl;
-            goto skip;
         } break;
 
         case CXCursor_FunctionDecl:
-        case CXCursor_VarDecl: try {
+        case CXCursor_VarDecl: {
             std::string label;
 
             CYList<CYFunctionParameter> parameters;
@@ -626,8 +656,13 @@ static CXChildVisitResult CYChildVisit(CXCursor cursor, CXCursor parent, CXClien
                 goto skip;
 
             if (code == NULL) {
+                value << "*";
                 CXType type(clang_getCursorType(cursor));
-                value << "*(typedef " << CYCXString(clang_getTypeSpelling(type)) << ").pointerTo()(dlsym(RTLD_DEFAULT,'" << label.substr(1) << "'))";
+                CYType *typed(CYDecodeType(type));
+                CYOptions options;
+                CYOutput out(*value.rdbuf(), options);
+                CYTypeExpression(typed).Output(out, CYNoBFC);
+                value << ".pointerTo()(dlsym(RTLD_DEFAULT,'" << label.substr(1) << "'))";
             } else {
                 CYOptions options;
                 CYOutput out(*value.rdbuf(), options);
@@ -635,28 +670,26 @@ static CXChildVisitResult CYChildVisit(CXCursor cursor, CXCursor parent, CXClien
                 function->Output(out, CYNoBFC);
                 //std::cerr << value.str() << std::endl;
             }
-        } catch (const CYException &error) {
-            CYPool pool;
-            //std::cerr << error.PoolCString(pool) << std::endl;
-            goto skip;
-        } break;
-
-        default: {
-            return CXChildVisit_Recurse;
         } break;
-    }
 
-    {
+        default:
+            result = CXChildVisit_Recurse;
+            goto skip;
+        break;
+    } {
         CYKey &key(baton.keys[name]);
-        if (key.priority_ < priority) {
+        if (key.priority_ <= priority) {
             key.priority_ = priority;
             key.code_ = value.str();
             key.flags_ = flags;
         }
+    } } catch (const CYException &error) {
+        CYPool pool;
+        //std::cerr << error.PoolCString(pool) << std::endl;
     }
 
   skip:
-    return CXChildVisit_Continue;
+    return result;
 }
 
 int main(int argc, const char *argv[]) {