]> git.saurik.com Git - cycript.git/commitdiff
Add () to non-properties and complete "real" ones.
authorJay Freeman (saurik) <saurik@saurik.com>
Fri, 8 Jan 2016 09:12:26 +0000 (01:12 -0800)
committerJay Freeman (saurik) <saurik@saurik.com>
Fri, 8 Jan 2016 09:12:26 +0000 (01:12 -0800)
Complete.cpp
ObjectiveC/Library.mm

index d3cc08e8c33520b7786cdf466a50a0f752144828..1d715d7a23b068863564b4e9f74b1ff4ada7736d 100644 (file)
@@ -19,6 +19,8 @@
 **/
 /* }}} */
 
+#include <typeinfo>
+
 #include "cycript.hpp"
 
 #include "Driver.hpp"
@@ -116,7 +118,8 @@ _visible char **CYComplete(const char *word, const std::string &line, CYUTF8Stri
         message = $ CYFalse();
 
     driver.script_ = $ CYScript($ CYExpress($C4(ParseExpression(pool,
-    "   function(object, prefix, word, message) {\n"
+    "   function(value, prefix, word, message) {\n"
+    "       var object = value;\n"
     "       var names = [];\n"
     "       var before = prefix.length;\n"
     "       prefix += word;\n"
@@ -126,10 +129,8 @@ _visible char **CYComplete(const char *word, const std::string &line, CYUTF8Stri
     "               if (name.substring(0, entire) == prefix)\n"
     "                   names.push(name);\n"
     "       } else do {\n"
-    "           if (object.hasOwnProperty(\"cy$complete\")) {\n"
-    "               names = names.concat(object.cy$complete(prefix, message));\n"
-    "               continue;\n"
-    "           }\n"
+    "           if (object.hasOwnProperty(\"cy$complete\"))\n"
+    "               names = names.concat(object.cy$complete.call(value, prefix, message));\n"
     "           try {\n"
     "               var local = Object.getOwnPropertyNames(object);\n"
     "           } catch (e) {\n"
@@ -173,8 +174,10 @@ _visible char **CYComplete(const char *word, const std::string &line, CYUTF8Stri
         _assert(value != NULL);
         element = value->next_;
 
+        _assert(value->value_ != NULL);
         CYString *string(dynamic_cast<CYString *>(value->value_));
-        _assert(string != NULL);
+        if (string == NULL)
+            CYThrow("string was actually %s", typeid(*value->value_).name());
 
         CYUTF8String completion;
         if (string->size_ != 0)
index 2c68efd6717a5de617fe67f515339f070c82f349..051f9b2453e07d24d1c3e809e4e7aa23001a404c 100644 (file)
@@ -46,6 +46,7 @@
 #include "Code.hpp"
 #include "Decode.hpp"
 #include "Error.hpp"
+#include "Functor.hpp"
 #include "JavaScript.hpp"
 #include "String.hpp"
 #include "Execute.hpp"
@@ -1897,16 +1898,22 @@ static bool Instance_deleteProperty(JSContextRef context, JSObjectRef object, JS
     } CYPoolCatch(false)
 } CYCatch(false) return /*XXX*/ false; }
 
-static void Instance_getPropertyNames_message(JSPropertyNameAccumulatorRef names, objc_method *method) {
-    const char *name(sel_getName(method_getName(method)));
-    if (strchr(name, ':') != NULL)
-        return;
+static void CYForEachProperty(CYPool &pool, Class _class, const Functor<void (objc_method *, const char *)> &code) {
+    for (; _class != Nil; _class = class_getSuperclass(_class)) {
+        unsigned int size;
+        objc_method **data(class_copyMethodList(_class, &size));
+        pool.atexit(free, data);
+
+        for (size_t i(0); i != size; ++i) {
+            objc_method *method(data[i]);
 
-    const char *type(method_getTypeEncoding(method));
-    if (type == NULL || *type == '\0' || *type == 'v')
-        return;
+            const char *name(sel_getName(method_getName(method)));
+            if (strchr(name, ':') != NULL)
+                continue;
 
-    JSPropertyNameAccumulatorAddName(names, CYJSString(name));
+            code(method, name);
+        }
+    }
 }
 
 static void Instance_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef names) {
@@ -1916,9 +1923,9 @@ static void Instance_getPropertyNames(JSContextRef context, JSObjectRef object,
     CYPool pool;
     Class _class(object_getClass(self));
 
-    {
+    for (Class current(_class); current != Nil; current = class_getSuperclass(current)) {
         unsigned int size;
-        objc_property_t *data(class_copyPropertyList(_class, &size));
+        objc_property_t *data(class_copyPropertyList(current, &size));
         pool.atexit(free, data);
 
         for (size_t i(0); i != size; ++i)
@@ -1926,14 +1933,9 @@ static void Instance_getPropertyNames(JSContextRef context, JSObjectRef object,
     }
 
     if (CYHasImplicitProperties(context, _class))
-        for (Class current(_class); current != nil; current = class_getSuperclass(current)) {
-            unsigned int size;
-            objc_method **data(class_copyMethodList(current, &size));
-            pool.atexit(free, data);
-
-            for (size_t i(0); i != size; ++i)
-                Instance_getPropertyNames_message(names, data[i]);
-        }
+        CYForEachProperty(pool, _class, fun([&](objc_method *method, const char *name) {
+            JSPropertyNameAccumulatorAddName(names, CYJSString(name));
+        }));
 
     CYPoolTry {
         // XXX: this is an evil hack to deal with NSProxy; fix elsewhere
@@ -1942,6 +1944,35 @@ static void Instance_getPropertyNames(JSContextRef context, JSObjectRef object,
     } CYPoolCatch()
 }
 
+static JSValueRef Instance_complete_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
+    if (!CYJSValueIsNSObject(context, _this))
+        return CYObjectMakeArray(context, 0, NULL);
+
+    Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(_this)));
+    id self(internal->value_);
+
+    _assert(count == 1 || count == 2);
+    CYPool pool;
+    Class _class(object_getClass(self));
+
+    CYUTF8String prefix(CYPoolUTF8String(pool, context, CYJSString(context, arguments[0])));
+
+    JSObjectRef array(NULL); {
+        CYArrayBuilder<1024> values(context, array);
+
+        CYForEachProperty(pool, _class, fun([&](objc_method *method, const char *name) {
+            if (!CYStartsWith(name, prefix))
+                return;
+            const char *type(method_getTypeEncoding(method));
+            if (type == NULL || *type == '\0' || *type == 'v')
+                return;
+            if (class_getProperty(_class, name) != NULL)
+                return;
+            values(CYCastJSValue(context, CYJSString(pool.strcat(name, "()", NULL))));
+        }));
+    } return array;
+} CYCatch(NULL) }
+
 static JSObjectRef Constructor_callAsConstructor(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
     auto internal(CYPrivate<Constructor>::Get(context, object));
     JSObjectRef value(CYMakeInstance(context, [internal->value_ alloc], Instance::Uninitialized));
@@ -2747,7 +2778,8 @@ static JSStaticValue FunctionInstance_staticValues[3] = {
     {NULL, NULL, NULL, 0}
 };
 
-static JSStaticFunction Instance_staticFunctions[6] = {
+static JSStaticFunction Instance_staticFunctions[7] = {
+    {"cy$complete", &Instance_complete_callAsFunction, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
     {"toCYON", &Instance_callAsFunction_toCYON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
     {"toJSON", &Instance_callAsFunction_toJSON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
     {"valueOf", &Instance_callAsFunction_valueOf, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},