From: Jay Freeman (saurik) Date: Fri, 8 Jan 2016 09:12:26 +0000 (-0800) Subject: Add () to non-properties and complete "real" ones. X-Git-Tag: v0.9.590~36 X-Git-Url: https://git.saurik.com/cycript.git/commitdiff_plain/e257405a21801819aa1f5262b0c373c03fabbd58 Add () to non-properties and complete "real" ones. --- diff --git a/Complete.cpp b/Complete.cpp index d3cc08e..1d715d7 100644 --- a/Complete.cpp +++ b/Complete.cpp @@ -19,6 +19,8 @@ **/ /* }}} */ +#include + #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(value->value_)); - _assert(string != NULL); + if (string == NULL) + CYThrow("string was actually %s", typeid(*value->value_).name()); CYUTF8String completion; if (string->size_ != 0) diff --git a/ObjectiveC/Library.mm b/ObjectiveC/Library.mm index 2c68efd..051f9b2 100644 --- a/ObjectiveC/Library.mm +++ b/ObjectiveC/Library.mm @@ -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 &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(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::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},