]> git.saurik.com Git - cycript.git/blobdiff - ObjectiveC/Library.mm
Rename cy$JSValueInContext to cy$valueOfInContext.
[cycript.git] / ObjectiveC / Library.mm
index 5b679cb86f5a0a238e0de75e8533cbc1f9c34e25..9b242d8471a9f21c6206f6617abae4d5ab98f9e2 100644 (file)
@@ -234,17 +234,12 @@ bool CYGetOffset(apr_pool_t *pool, JSContextRef context, NSString *value, ssize_
 }
 
 static JSClassRef Instance_;
+
 static JSClassRef ArrayInstance_;
+static JSClassRef FunctionInstance_;
 static JSClassRef ObjectInstance_;
 static JSClassRef StringInstance_;
 
-static JSClassRef *Instances_[] = {
-    &Instance_,
-    &ArrayInstance_,
-    &ObjectInstance_,
-    &StringInstance_,
-};
-
 static JSClassRef Internal_;
 static JSClassRef Message_;
 static JSClassRef Messages_;
@@ -271,6 +266,7 @@ static Class NSBoolNumber_;
 #endif
 
 static Class NSArray_;
+static Class NSBlock_;
 static Class NSDictionary_;
 static Class NSString_;
 static Class Object_;
@@ -278,13 +274,6 @@ static Class Object_;
 static Type_privateData *Object_type;
 static Type_privateData *Selector_type;
 
-static bool CYValueIsObjectOfClassInstance(JSContextRef context, JSValueRef value) {
-    for (size_t i(0); i != sizeof(Instances_) / sizeof(Instances_[0]); ++i)
-        if (JSValueIsObjectOfClass(context, value, *Instances_[i]))
-            return true;
-    return false;
-}
-
 Type_privateData *Instance::GetType() const {
     return Object_type;
 }
@@ -315,6 +304,8 @@ JSValueRef CYGetClassPrototype(JSContextRef context, id self) {
 
     if (self == NSArray_)
         prototype = CYGetCachedObject(context, CYJSString("ArrayInstance_prototype"));
+    else if (self == NSBlock_)
+        prototype = CYGetCachedObject(context, CYJSString("FunctionInstance_prototype"));
     else if (self == NSDictionary_)
         prototype = CYGetCachedObject(context, CYJSString("ObjectInstance_prototype"));
     else if (self == NSString_)
@@ -394,12 +385,11 @@ JSObjectRef CYMakeInstance(JSContextRef context, id object, bool transient) {
 
 @interface NSObject (Cycript)
 
-- (JSValueRef) cy$JSValueInContext:(JSContextRef)context;
+- (JSValueRef) cy$valueOfInContext:(JSContextRef)context;
 - (JSType) cy$JSType;
 
 - (NSObject *) cy$toJSON:(NSString *)key;
 - (NSString *) cy$toCYON;
-- (NSString *) cy$toKey;
 
 - (bool) cy$hasProperty:(NSString *)name;
 - (NSObject *) cy$getProperty:(NSString *)name;
@@ -413,7 +403,7 @@ JSObjectRef CYMakeInstance(JSContextRef context, id object, bool transient) {
 
 @protocol Cycript
 - (id) cy$box;
-- (JSValueRef) cy$JSValueInContext:(JSContextRef)context;
+- (JSValueRef) cy$valueOfInContext:(JSContextRef)context;
 @end
 
 NSString *CYCastNSCYON(id value) {
@@ -616,7 +606,7 @@ NSObject *CYCastNSObject_(apr_pool_t *pool, JSContextRef context, JSObjectRef ob
 }
 
 NSObject *CYCastNSObject(apr_pool_t *pool, JSContextRef context, JSObjectRef object) {
-    if (!CYValueIsObjectOfClassInstance(context, object))
+    if (!JSValueIsObjectOfClass(context, object, Instance_))
         return CYCastNSObject_(pool, context, object);
     else {
         Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(object)));
@@ -776,6 +766,13 @@ NSObject *CYCopyNSObject(apr_pool_t *pool, JSContextRef context, JSValueRef valu
 
 @end
 /* }}} */
+/* Bridge: NSBlock {{{ */
+#ifdef __APPLE__
+@interface NSBlock
+- (void) invoke;
+@end
+#endif
+/* }}} */
 /* Bridge: NSBoolNumber {{{ */
 #ifndef __APPLE__
 @implementation NSBoolNumber (Cycript)
@@ -792,7 +789,7 @@ NSObject *CYCopyNSObject(apr_pool_t *pool, JSContextRef context, JSValueRef valu
     return [self boolValue] ? @"@true" : @"@false";
 }
 
-- (JSValueRef) cy$JSValueInContext:(JSContextRef)context { CYObjectiveTry_(context) {
+- (JSValueRef) cy$valueOfInContext:(JSContextRef)context { CYObjectiveTry_(context) {
     return CYCastJSValue(context, (bool) [self boolValue]);
 } CYObjectiveCatch }
 
@@ -821,7 +818,7 @@ NSObject *CYCopyNSObject(apr_pool_t *pool, JSContextRef context, JSValueRef valu
             [json appendString:@","];
         else
             comma = true;
-        [json appendString:[key cy$toKey]];
+        [json appendString:CYCastNSCYON(key)];
         [json appendString:@":"];
         NSObject *object([self objectForKey:key]);
         [json appendString:CYCastNSCYON(object)];
@@ -952,7 +949,7 @@ NSObject *CYCopyNSObject(apr_pool_t *pool, JSContextRef context, JSValueRef valu
     return [self cy$JSType] != kJSTypeBoolean ? [NSString stringWithFormat:@"@%@", self] : [self boolValue] ? @"@true" : @"@false";
 }
 
-- (JSValueRef) cy$JSValueInContext:(JSContextRef)context { CYObjectiveTry_(context) {
+- (JSValueRef) cy$valueOfInContext:(JSContextRef)context { CYObjectiveTry_(context) {
     return [self cy$JSType] != kJSTypeBoolean ? CYCastJSValue(context, [self doubleValue]) : CYCastJSValue(context, [self boolValue]);
 } CYObjectiveCatch }
 
@@ -982,7 +979,7 @@ NSObject *CYCopyNSObject(apr_pool_t *pool, JSContextRef context, JSValueRef valu
     return self;
 }
 
-- (JSValueRef) cy$JSValueInContext:(JSContextRef)context { CYObjectiveTry_(context) {
+- (JSValueRef) cy$valueOfInContext:(JSContextRef)context { CYObjectiveTry_(context) {
     return NULL;
 } CYObjectiveCatch }
 
@@ -998,10 +995,6 @@ NSObject *CYCopyNSObject(apr_pool_t *pool, JSContextRef context, JSValueRef valu
     return [[self cy$toJSON:@""] cy$toCYON];
 }
 
-- (NSString *) cy$toKey {
-    return [self cy$toCYON];
-}
-
 - (bool) cy$hasProperty:(NSString *)name {
     return false;
 }
@@ -1064,12 +1057,6 @@ NSObject *CYCopyNSObject(apr_pool_t *pool, JSContextRef context, JSValueRef valu
     return CYCastNSString(NULL, CYUTF8String(value.c_str(), value.size()));
 }
 
-- (NSString *) cy$toKey {
-    if (CYIsKey(CYCastUTF8String(self)))
-        return self;
-    return [self cy$toCYON];
-}
-
 - (bool) cy$hasProperty:(NSString *)name {
     if ([name isEqualToString:@"length"])
         return true;
@@ -1113,7 +1100,7 @@ NSObject *CYCopyNSObject(apr_pool_t *pool, JSContextRef context, JSValueRef valu
     return false;
 }
 
-- (JSValueRef) cy$JSValueInContext:(JSContextRef)context { CYObjectiveTry_(context) {
+- (JSValueRef) cy$valueOfInContext:(JSContextRef)context { CYObjectiveTry_(context) {
     return CYCastJSValue(context, CYJSString(context, self));
 } CYObjectiveCatch }
 
@@ -1134,7 +1121,7 @@ NSObject *CYCopyNSObject(apr_pool_t *pool, JSContextRef context, JSValueRef valu
     return @"undefined";
 }
 
-- (JSValueRef) cy$JSValueInContext:(JSContextRef)context { CYObjectiveTry_(context) {
+- (JSValueRef) cy$valueOfInContext:(JSContextRef)context { CYObjectiveTry_(context) {
     return CYJSUndefined(context);
 } CYObjectiveCatch }
 
@@ -1846,13 +1833,89 @@ static JSObjectRef Instance_callAsConstructor(JSContextRef context, JSObjectRef
     return value;
 } CYCatch }
 
+static JSValueRef Instance_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
+    Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(object)));
+    id self(internal->GetValue());
+
+    if (![self isKindOfClass:NSBlock_])
+        CYThrow("non-NSBlock object is not a function");
+
+    struct BlockDescriptor1 {
+        unsigned long int reserved;
+        unsigned long int size;
+    };
+
+    struct BlockDescriptor2 {
+        void (*copy_helper)(void *dst, void *src);
+        void (*dispose_helper)(void *src);
+    };
+
+    struct BlockDescriptor3 {
+        const char *signature;
+        const char *layout;
+    };
+
+    struct BlockLiteral {
+        Class isa;
+        int flags;
+        int reserved;
+        void (*invoke)(void *, ...);
+        void *descriptor;
+    } *literal = reinterpret_cast<BlockLiteral *>(self);
+
+    enum {
+        BLOCK_DEALLOCATING = 0x0001,
+        BLOCK_REFCOUNT_MASK = 0xfffe,
+        BLOCK_NEEDS_FREE = 1 << 24,
+        BLOCK_HAS_COPY_DISPOSE = 1 << 25,
+        BLOCK_HAS_CTOR = 1 << 26,
+        BLOCK_IS_GC = 1 << 27,
+        BLOCK_IS_GLOBAL = 1 << 28,
+        BLOCK_HAS_STRET = 1 << 29,
+        BLOCK_HAS_SIGNATURE = 1 << 30,
+    };
+
+    if ((literal->flags & BLOCK_HAS_SIGNATURE) != 0) {
+        uint8_t *descriptor(reinterpret_cast<uint8_t *>(literal->descriptor));
+        descriptor += sizeof(BlockDescriptor1);
+        if ((literal->flags & BLOCK_HAS_COPY_DISPOSE) != 0)
+            descriptor += sizeof(BlockDescriptor2);
+        BlockDescriptor3 *descriptor3(reinterpret_cast<BlockDescriptor3 *>(descriptor));
+
+        if (const char *type = descriptor3->signature) {
+            CYPool pool;
+
+            void *setup[1];
+            setup[0] = &self;
+
+            sig::Signature signature;
+            sig::Parse(pool, &signature, type, &Structor_);
+
+            ffi_cif cif;
+            sig::sig_ffi_cif(pool, &sig::ObjectiveC, &signature, &cif);
+
+            void (*function)() = reinterpret_cast<void (*)()>(literal->invoke);
+            return CYCallFunction(pool, context, 1, setup, count, arguments, false, exception, &signature, &cif, function);
+        }
+    }
+
+    if (count != 0)
+        CYThrow("NSBlock without signature field passed arguments");
+
+    CYPoolTry {
+        [self invoke];
+    } CYPoolCatch(NULL);
+
+    return NULL;
+} CYCatch }
+
 static bool Instance_hasInstance(JSContextRef context, JSObjectRef constructor, JSValueRef instance, JSValueRef *exception) { CYTry {
     Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate((JSObjectRef) constructor)));
     Class _class(internal->GetValue());
     if (!CYIsClass(_class))
         return false;
 
-    if (CYValueIsObjectOfClassInstance(context, instance)) {
+    if (JSValueIsObjectOfClass(context, instance, Instance_)) {
         Instance *linternal(reinterpret_cast<Instance *>(JSObjectGetPrivate((JSObjectRef) instance)));
         // XXX: this isn't always safe
         return [linternal->GetValue() isKindOfClass:_class];
@@ -2170,7 +2233,7 @@ static JSValueRef $objc_msgSend(JSContextRef context, JSObjectRef object, JSObje
         self = internal->GetValue();
         _class = internal->class_;;
         uninitialized = false;
-    } else if (CYValueIsObjectOfClassInstance(context, arguments[0])) {
+    } else if (JSValueIsObjectOfClass(context, arguments[0], Instance_)) {
         Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate((JSObjectRef) arguments[0])));
         self = internal->GetValue();
         _class = nil;
@@ -2318,7 +2381,7 @@ static JSValueRef Instance_getProperty_messages(JSContextRef context, JSObjectRe
 }
 
 static JSValueRef Instance_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
-    if (!CYValueIsObjectOfClassInstance(context, _this))
+    if (!JSValueIsObjectOfClass(context, _this, Instance_))
         return NULL;
 
     Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(_this)));
@@ -2326,7 +2389,7 @@ static JSValueRef Instance_callAsFunction_toCYON(JSContextRef context, JSObjectR
 } CYCatch }
 
 static JSValueRef Instance_callAsFunction_toJSON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
-    if (!CYValueIsObjectOfClassInstance(context, _this))
+    if (!JSValueIsObjectOfClass(context, _this, Instance_))
         return NULL;
 
     Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(_this)));
@@ -2343,23 +2406,23 @@ static JSValueRef Instance_callAsFunction_toJSON(JSContextRef context, JSObjectR
 } CYCatch return /*XXX*/ NULL; }
 
 static JSValueRef Instance_callAsFunction_valueOf(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
-    if (!CYValueIsObjectOfClassInstance(context, _this))
+    if (!JSValueIsObjectOfClass(context, _this, Instance_))
         return NULL;
 
     Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(_this)));
     id value(internal->GetValue());
 
-    if (![value respondsToSelector:@selector(cy$JSValueInContext:)])
+    if (![value respondsToSelector:@selector(cy$valueOfInContext:)])
         return _this;
 
-    if (JSValueRef result = [value cy$JSValueInContext:context])
+    if (JSValueRef result = [value cy$valueOfInContext:context])
         return result;
 
     return _this;
 } CYCatch return /*XXX*/ NULL; }
 
 static JSValueRef Instance_callAsFunction_toPointer(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
-    if (!CYValueIsObjectOfClassInstance(context, _this))
+    if (!JSValueIsObjectOfClass(context, _this, Instance_))
         return NULL;
 
     Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(_this)));
@@ -2368,7 +2431,7 @@ static JSValueRef Instance_callAsFunction_toPointer(JSContextRef context, JSObje
 } CYCatch return /*XXX*/ NULL; }
 
 static JSValueRef Instance_callAsFunction_toString(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry {
-    if (!CYValueIsObjectOfClassInstance(context, _this))
+    if (!JSValueIsObjectOfClass(context, _this, Instance_))
         return NULL;
 
     Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(_this)));
@@ -2475,6 +2538,7 @@ void CYObjectiveC_Initialize() { /*XXX*/ JSContextRef context(NULL); CYPoolTry {
 #endif
 
     NSArray_ = objc_getClass("NSArray");
+    NSBlock_ = objc_getClass("NSBlock");
     NSDictionary_ = objc_getClass("NSDictionary");
     NSString_ = objc_getClass("NSString");
     Object_ = objc_getClass("Object");
@@ -2491,6 +2555,7 @@ void CYObjectiveC_Initialize() { /*XXX*/ JSContextRef context(NULL); CYPoolTry {
     definition.deleteProperty = &Instance_deleteProperty;
     definition.getPropertyNames = &Instance_getPropertyNames;
     definition.callAsConstructor = &Instance_callAsConstructor;
+    definition.callAsFunction = &Instance_callAsFunction;
     definition.hasInstance = &Instance_hasInstance;
     definition.finalize = &CYFinalize;
     Instance_ = JSClassCreate(&definition);
@@ -2498,6 +2563,9 @@ void CYObjectiveC_Initialize() { /*XXX*/ JSContextRef context(NULL); CYPoolTry {
     definition.className = "ArrayInstance";
     ArrayInstance_ = JSClassCreate(&definition);
 
+    definition.className = "FunctionInstance";
+    FunctionInstance_ = JSClassCreate(&definition);
+
     definition.className = "ObjectInstance";
     ObjectInstance_ = JSClassCreate(&definition);
 
@@ -2628,6 +2696,12 @@ void CYObjectiveC_SetupContext(JSContextRef context) { CYPoolTry {
     JSObjectRef Array_prototype(CYGetCachedObject(context, CYJSString("Array_prototype")));
     JSObjectSetPrototype(context, ArrayInstance_prototype, Array_prototype);
 
+    JSObjectRef FunctionInstance(JSObjectMakeConstructor(context, FunctionInstance_, NULL));
+    JSObjectRef FunctionInstance_prototype(CYCastJSObject(context, CYGetProperty(context, FunctionInstance, prototype_s)));
+    CYSetProperty(context, cy, CYJSString("FunctionInstance_prototype"), FunctionInstance_prototype);
+    JSObjectRef Function_prototype(CYGetCachedObject(context, CYJSString("Function_prototype")));
+    JSObjectSetPrototype(context, FunctionInstance_prototype, Function_prototype);
+
     JSObjectRef ObjectInstance(JSObjectMakeConstructor(context, ObjectInstance_, NULL));
     JSObjectRef ObjectInstance_prototype(CYCastJSObject(context, CYGetProperty(context, ObjectInstance, prototype_s)));
     CYSetProperty(context, cy, CYJSString("ObjectInstance_prototype"), ObjectInstance_prototype);
@@ -2653,7 +2727,6 @@ void CYObjectiveC_SetupContext(JSContextRef context) { CYPoolTry {
 
     CYSetProperty(context, all, CYJSString("objc_msgSend"), &$objc_msgSend, kJSPropertyAttributeDontEnum);
 
-    JSObjectRef Function_prototype(CYGetCachedObject(context, CYJSString("Function_prototype")));
     JSObjectSetPrototype(context, CYCastJSObject(context, CYGetProperty(context, Message, prototype_s)), Function_prototype);
     JSObjectSetPrototype(context, CYCastJSObject(context, CYGetProperty(context, Selector, prototype_s)), Function_prototype);
 } CYPoolCatch() }