X-Git-Url: https://git.saurik.com/cycript.git/blobdiff_plain/e23a907053d46f6db4b3123316ef8d671fb3714a..9ec7dd188b51ba8245b33ed23be1a6202a0e749b:/ObjectiveC/Library.mm diff --git a/ObjectiveC/Library.mm b/ObjectiveC/Library.mm index e3b8917..5863e95 100644 --- a/ObjectiveC/Library.mm +++ b/ObjectiveC/Library.mm @@ -246,6 +246,7 @@ static JSClassRef FunctionInstance_; static JSClassRef ObjectInstance_; static JSClassRef StringInstance_; +static JSClassRef Class_; static JSClassRef Internal_; static JSClassRef Message_; static JSClassRef Messages_; @@ -290,9 +291,11 @@ Type_privateData *Selector_privateData::GetType() const { static JSValueRef Instance_callAsFunction_toString(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception); -JSValueRef CYGetClassPrototype(JSContextRef context, id self) { +JSValueRef CYGetClassPrototype(JSContextRef context, Class self, bool meta) { if (self == nil) return CYGetCachedObject(context, CYJSString("Instance_prototype")); + else if (meta && !class_isMetaClass(self)) + return CYGetCachedObject(context, CYJSString("Class_prototype")); JSObjectRef global(CYGetGlobalObject(context)); JSObjectRef cy(CYCastJSObject(context, CYGetProperty(context, global, cy_s))); @@ -317,7 +320,7 @@ JSValueRef CYGetClassPrototype(JSContextRef context, id self) { else if (self == NSString_) prototype = CYGetCachedObject(context, CYJSString("StringInstance_prototype")); else - prototype = CYGetClassPrototype(context, class_getSuperclass(self)); + prototype = CYGetClassPrototype(context, class_getSuperclass(self), meta); JSObjectRef object(JSObjectMake(context, _class, NULL)); JSObjectSetPrototype(context, object, prototype); @@ -326,14 +329,14 @@ JSValueRef CYGetClassPrototype(JSContextRef context, id self) { return object; } -JSObjectRef Messages::Make(JSContextRef context, Class _class, bool array) { +_finline JSValueRef CYGetClassPrototype(JSContextRef context, Class self) { + return CYGetClassPrototype(context, self, class_isMetaClass(self)); +} + +JSObjectRef Messages::Make(JSContextRef context, Class _class) { JSObjectRef value(JSObjectMake(context, Messages_, new Messages(_class))); - if (_class == NSArray_) - array = true; if (Class super = class_getSuperclass(_class)) - JSObjectSetPrototype(context, value, Messages::Make(context, super, array)); - /*else if (array) - JSObjectSetPrototype(context, value, Array_prototype_);*/ + JSObjectSetPrototype(context, value, Messages::Make(context, super)); return value; } @@ -399,6 +402,7 @@ JSObjectRef CYMakeInstance(JSContextRef context, id object, bool transient) { - (bool) cy$hasProperty:(NSString *)name; - (NSObject *) cy$getProperty:(NSString *)name; +- (JSValueRef) cy$getProperty:(NSString *)name inContext:(JSContextRef)context; - (bool) cy$setProperty:(NSString *)name to:(NSObject *)value; - (bool) cy$deleteProperty:(NSString *)name; - (void) cy$getPropertyNames:(JSPropertyNameAccumulatorRef)names inContext:(JSContextRef)context; @@ -594,6 +598,10 @@ struct PropertyAttributes { @end /* }}} */ +_finline bool CYJSValueIsNSObject(JSContextRef context, JSValueRef value) { + return JSValueIsObjectOfClass(context, value, Instance_); +} + _finline bool CYJSValueIsInstanceOfCachedConstructor(JSContextRef context, JSValueRef value, JSStringRef cache) { JSValueRef exception(NULL); JSObjectRef constructor(CYGetCachedObject(context, cache)); @@ -603,7 +611,7 @@ _finline bool CYJSValueIsInstanceOfCachedConstructor(JSContextRef context, JSVal } NSObject *CYCastNSObject(apr_pool_t *pool, JSContextRef context, JSObjectRef object) { - if (JSValueIsObjectOfClass(context, object, Instance_)) { + if (CYJSValueIsNSObject(context, object)) { Instance *internal(reinterpret_cast(JSObjectGetPrivate(object))); return internal->GetValue(); } @@ -730,15 +738,6 @@ NSObject *CYCopyNSObject(apr_pool_t *pool, JSContextRef context, JSValueRef valu } - (NSObject *) cy$getProperty:(NSString *)name { - if ([name isEqualToString:@"length"]) { - NSUInteger count([self count]); -#ifdef __APPLE__ - return [NSNumber numberWithUnsignedInteger:count]; -#else - return [NSNumber numberWithUnsignedInt:count]; -#endif - } - size_t index(CYGetIndex(name)); if (index == _not(size_t) || index >= [self count]) return [super cy$getProperty:name]; @@ -746,6 +745,15 @@ NSObject *CYCopyNSObject(apr_pool_t *pool, JSContextRef context, JSValueRef valu return [self objectAtIndex:index]; } +- (JSValueRef) cy$getProperty:(NSString *)name inContext:(JSContextRef)context { + CYObjectiveTry_(context) { + if ([name isEqualToString:@"length"]) + return CYCastJSValue(context, [self count]); + } CYObjectiveCatch + + return [super cy$getProperty:name inContext:context]; +} + - (void) cy$getPropertyNames:(JSPropertyNameAccumulatorRef)names inContext:(JSContextRef)context { [super cy$getPropertyNames:names inContext:context]; @@ -997,6 +1005,12 @@ NSObject *CYCopyNSObject(apr_pool_t *pool, JSContextRef context, JSValueRef valu return nil; } +- (JSValueRef) cy$getProperty:(NSString *)name inContext:(JSContextRef)context { CYObjectiveTry_(context) { + if (NSObject *value = [self cy$getProperty:name]) + return CYCastJSValue(context, value); + return NULL; +} CYObjectiveCatch } + - (bool) cy$setProperty:(NSString *)name to:(NSObject *)value { return false; } @@ -1045,9 +1059,6 @@ NSObject *CYCopyNSObject(apr_pool_t *pool, JSContextRef context, JSValueRef valu } - (bool) cy$hasProperty:(NSString *)name { - if ([name isEqualToString:@"length"]) - return true; - size_t index(CYGetIndex(name)); if (index == _not(size_t) || index >= [self length]) return [super cy$hasProperty:name]; @@ -1056,15 +1067,6 @@ NSObject *CYCopyNSObject(apr_pool_t *pool, JSContextRef context, JSValueRef valu } - (NSObject *) cy$getProperty:(NSString *)name { - if ([name isEqualToString:@"length"]) { - NSUInteger count([self length]); -#ifdef __APPLE__ - return [NSNumber numberWithUnsignedInteger:count]; -#else - return [NSNumber numberWithUnsignedInt:count]; -#endif - } - size_t index(CYGetIndex(name)); if (index == _not(size_t) || index >= [self length]) return [super cy$getProperty:name]; @@ -1082,11 +1084,6 @@ NSObject *CYCopyNSObject(apr_pool_t *pool, JSContextRef context, JSValueRef valu } } -// XXX: this might be overly restrictive for NSString; I think I need a half-way between /injecting/ implicit properties and /accepting/ implicit properties -+ (bool) cy$hasImplicitProperties { - return false; -} - - (JSValueRef) cy$valueOfInContext:(JSContextRef)context { CYObjectiveTry_(context) { return CYCastJSValue(context, CYJSString(context, self)); } CYObjectiveCatch } @@ -1100,7 +1097,7 @@ NSObject *CYCopyNSObject(apr_pool_t *pool, JSContextRef context, JSValueRef valu return kJSTypeUndefined; } -- (NSString *) cy$toCYON { +- (NSString *) cy$toCYON:(bool)objective { NSString *value(@"undefined"); return value; // XXX: maybe use the below code, adding @undefined? //return objective ? value : [NSString stringWithFormat:@"@%@", value]; @@ -1115,8 +1112,7 @@ NSObject *CYCopyNSObject(apr_pool_t *pool, JSContextRef context, JSValueRef valu static bool CYIsClass(id self) { #ifdef __APPLE__ - // XXX: this is a lame object_isClass - return class_getInstanceMethod(object_getClass(self), @selector(alloc)) != NULL; + return class_isMetaClass(object_getClass(self)); #else return GSObjCIsClass(self); #endif @@ -1489,21 +1485,13 @@ static const char *CYPoolTypeEncoding(apr_pool_t *pool, JSContextRef context, SE return NULL; } -static void MessageClosure_(ffi_cif *cif, void *result, void **arguments, void *arg) { - Closure_privateData *internal(reinterpret_cast(arg)); - - JSContextRef context(internal->context_); - - size_t count(internal->cif_.nargs); - JSValueRef values[count]; - - for (size_t index(0); index != count; ++index) - values[index] = CYFromFFI(context, internal->signature_.elements[1 + index].type, internal->cif_.arg_types[index], arguments[index]); - +static JSValueRef MessageAdapter_(JSContextRef context, size_t count, JSValueRef values[], JSObjectRef function) { JSObjectRef _this(CYCastJSObject(context, values[0])); + return CYCallAsFunction(context, function, _this, count - 2, values + 2); +} - JSValueRef value(CYCallAsFunction(context, internal->function_, _this, count - 2, values + 2)); - CYPoolFFI(NULL, context, internal->signature_.elements[0].type, internal->cif_.rtype, result, value); +static void MessageClosure_(ffi_cif *cif, void *result, void **arguments, void *arg) { + CYExecuteClosure(cif, result, arguments, arg, &MessageAdapter_); } static JSObjectRef CYMakeMessage(JSContextRef context, SEL sel, IMP imp, const char *type) { @@ -1681,8 +1669,8 @@ static JSValueRef Instance_getProperty(JSContextRef context, JSObjectRef object, return value; CYPoolTry { - if (NSObject *data = [self cy$getProperty:name]) - return CYCastJSValue(context, data); + if (JSValueRef value = [self cy$getProperty:name inContext:context]) + return value; } CYPoolCatch(NULL) const char *string(CYPoolCString(pool, context, name)); @@ -1918,7 +1906,7 @@ static bool Instance_hasInstance(JSContextRef context, JSObjectRef constructor, if (!CYIsClass(_class)) return false; - if (JSValueIsObjectOfClass(context, instance, Instance_)) { + if (CYJSValueIsNSObject(context, instance)) { Instance *linternal(reinterpret_cast(JSObjectGetPrivate((JSObjectRef) instance))); // XXX: this isn't always safe return [linternal->GetValue() isKindOfClass:_class]; @@ -2236,7 +2224,7 @@ static JSValueRef $objc_msgSend(JSContextRef context, JSObjectRef object, JSObje self = internal->GetValue(); _class = internal->class_;; uninitialized = false; - } else if (JSValueIsObjectOfClass(context, arguments[0], Instance_)) { + } else if (CYJSValueIsNSObject(context, arguments[0])) { Instance *internal(reinterpret_cast(JSObjectGetPrivate((JSObjectRef) arguments[0]))); self = internal->GetValue(); _class = nil; @@ -2348,7 +2336,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 (!JSValueIsObjectOfClass(context, _this, Instance_)) + if (!CYJSValueIsNSObject(context, _this)) return NULL; Instance *internal(reinterpret_cast(JSObjectGetPrivate(_this))); @@ -2356,7 +2344,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 (!JSValueIsObjectOfClass(context, _this, Instance_)) + if (!CYJSValueIsNSObject(context, _this)) return NULL; Instance *internal(reinterpret_cast(JSObjectGetPrivate(_this))); @@ -2379,7 +2367,7 @@ 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 (!JSValueIsObjectOfClass(context, _this, Instance_)) + if (!CYJSValueIsNSObject(context, _this)) return NULL; Instance *internal(reinterpret_cast(JSObjectGetPrivate(_this))); @@ -2395,7 +2383,7 @@ static JSValueRef Instance_callAsFunction_valueOf(JSContextRef context, JSObject } 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 (!JSValueIsObjectOfClass(context, _this, Instance_)) + if (!CYJSValueIsNSObject(context, _this)) return NULL; Instance *internal(reinterpret_cast(JSObjectGetPrivate(_this))); @@ -2404,21 +2392,40 @@ 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 (!JSValueIsObjectOfClass(context, _this, Instance_)) + if (!CYJSValueIsNSObject(context, _this)) return NULL; Instance *internal(reinterpret_cast(JSObjectGetPrivate(_this))); id value(internal->GetValue()); - if (value == nil) - return CYCastJSValue(context, "nil"); - CYPoolTry { // XXX: this seems like a stupid implementation; what if it crashes? why not use the CYONifier backend? return CYCastJSValue(context, CYJSString(context, [value description])); } CYPoolCatch(NULL) } CYCatch return /*XXX*/ NULL; } +static JSValueRef Class_callAsFunction_pointerTo(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry { + if (!CYJSValueIsNSObject(context, _this)) + return NULL; + + Instance *internal(reinterpret_cast(JSObjectGetPrivate(_this))); + id value(internal->GetValue()); + + if (!CYIsClass(value)) + CYThrow("non-Class object cannot be used as Type"); + + // XXX: this is a very silly implementation + + std::ostringstream type; + type << "@\""; + type << class_getName(value); + type << "\""; + + CYPoolTry { + return CYMakeType(context, type.str().c_str()); + } CYPoolCatch(NULL) +} CYCatch return /*XXX*/ NULL; } + static JSValueRef Selector_callAsFunction_toString(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry { Selector_privateData *internal(reinterpret_cast(JSObjectGetPrivate(_this))); return CYCastJSValue(context, sel_getName(internal->GetValue())); @@ -2481,6 +2488,11 @@ static JSStaticFunction Instance_staticFunctions[7] = { {NULL, NULL, 0} }; +static JSStaticFunction Class_staticFunctions[2] = { + {"pointerTo", &Class_callAsFunction_pointerTo, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, + {NULL, NULL, 0} +}; + static JSStaticFunction Internal_staticFunctions[2] = { {"$cya", &Internal_callAsFunction_$cya, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, {NULL, NULL, 0} @@ -2550,14 +2562,19 @@ 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); definition.className = "StringInstance"; StringInstance_ = JSClassCreate(&definition); - definition.className = "FunctionInstance"; - FunctionInstance_ = JSClassCreate(&definition); + definition = kJSClassDefinitionEmpty; + definition.className = "Class"; + definition.staticFunctions = Class_staticFunctions; + Class_ = JSClassCreate(&definition); definition = kJSClassDefinitionEmpty; definition.className = "Internal"; @@ -2665,6 +2682,7 @@ void CYObjectiveC_SetupContext(JSContextRef context) { CYPoolTry { CYSetProperty(context, ObjectiveC, CYJSString("images"), JSObjectMake(context, ObjectiveC_Images_, NULL)); #endif + JSObjectRef Class(JSObjectMakeConstructor(context, Class_, NULL)); JSObjectRef Instance(JSObjectMakeConstructor(context, Instance_, &Instance_new)); JSObjectRef Message(JSObjectMakeConstructor(context, Message_, NULL)); JSObjectRef Selector(JSObjectMakeConstructor(context, Selector_, &Selector_new)); @@ -2697,6 +2715,10 @@ void CYObjectiveC_SetupContext(JSContextRef context) { CYPoolTry { JSObjectRef String_prototype(CYGetCachedObject(context, CYJSString("String_prototype"))); JSObjectSetPrototype(context, StringInstance_prototype, String_prototype); + JSObjectRef Class_prototype(CYCastJSObject(context, CYGetProperty(context, Class, prototype_s))); + CYSetProperty(context, cy, CYJSString("Class_prototype"), Class_prototype); + JSObjectSetPrototype(context, Class_prototype, Instance_prototype); + CYSetProperty(context, cycript, CYJSString("Instance"), Instance); CYSetProperty(context, cycript, CYJSString("Selector"), Selector); CYSetProperty(context, cycript, CYJSString("Super"), Super);