From 7b184c00032216da435268c698a4c2260faf4eb8 Mon Sep 17 00:00:00 2001 From: "Jay Freeman (saurik)" <saurik@saurik.com> Date: Fri, 16 Oct 2009 19:05:51 +0000 Subject: [PATCH] Fleshed out support for &, reworked nil internally, setup new Instance(), and implemented hasProperty across-the-board. --- Library.mm | 250 +++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 195 insertions(+), 55 deletions(-) diff --git a/Library.mm b/Library.mm index 2eeb1c7..0dce485 100644 --- a/Library.mm +++ b/Library.mm @@ -169,6 +169,8 @@ struct CYData { } }; +class Type_privateData; + struct CYValue : CYData { @@ -186,6 +188,10 @@ struct CYValue : value_(rhs.value_) { } + + virtual Type_privateData *GetType() const { + return NULL; + } }; struct Selector_privateData : @@ -199,6 +205,8 @@ struct Selector_privateData : SEL GetValue() const { return reinterpret_cast<SEL>(value_); } + + virtual Type_privateData *GetType() const; }; struct Instance : @@ -235,6 +243,8 @@ struct Instance : bool IsUninitialized() const { return (flags_ & Uninitialized) != 0; } + + virtual Type_privateData *GetType() const; }; struct Internal : @@ -353,6 +363,9 @@ void Structor_(apr_pool_t *pool, const char *name, const char *types, sig::Type struct Type_privateData : CYData { + static Type_privateData *Object; + static Type_privateData *Selector; + ffi_type *ffi_; sig::Type *type_; @@ -407,6 +420,17 @@ struct Type_privateData : } }; +Type_privateData *Type_privateData::Object; +Type_privateData *Type_privateData::Selector; + +Type_privateData *Instance::GetType() const { + return Type_privateData::Object; +} + +Type_privateData *Selector_privateData::GetType() const { + return Type_privateData::Selector; +} + struct Pointer : CYValue { @@ -562,6 +586,7 @@ NSString *CYPoolNSCYON(apr_pool_t *pool, id value); - (NSString *) cy$toCYON; - (NSString *) cy$toKey; +- (bool) cy$hasProperty:(NSString *)name; - (NSObject *) cy$getProperty:(NSString *)name; - (bool) cy$setProperty:(NSString *)name to:(NSObject *)value; - (bool) cy$deleteProperty:(NSString *)name; @@ -696,19 +721,19 @@ struct PropertyAttributes { return [self cy$toCYON]; } +- (bool) cy$hasProperty:(NSString *)name { + return false; +} + - (NSObject *) cy$getProperty:(NSString *)name { - /*if (![name isEqualToString:@"prototype"]) - NSLog(@"get:%@", name);*/ return nil; } - (bool) cy$setProperty:(NSString *)name to:(NSObject *)value { - //NSLog(@"set:%@", name); return false; } - (bool) cy$deleteProperty:(NSString *)name { - //NSLog(@"delete:%@", name); return false; } @@ -766,7 +791,7 @@ NSString *NSCFType$cy$toJSON(id self, SEL sel, NSString *key) { [json appendString:@","]; else comma = true; - if ([object cy$JSType] != kJSTypeUndefined) + if (object == nil || [object cy$JSType] != kJSTypeUndefined) [json appendString:CYPoolNSCYON(NULL, object)]; else { [json appendString:@","]; @@ -778,6 +803,17 @@ NSString *NSCFType$cy$toJSON(id self, SEL sel, NSString *key) { return json; } +- (bool) cy$hasProperty:(NSString *)name { + if ([name isEqualToString:@"length"]) + return true; + + ssize_t index; + if (!CYGetIndex(NULL, name, index) || index < 0 || index >= static_cast<ssize_t>([self count])) + return [super cy$hasProperty:name]; + else + return true; +} + - (NSObject *) cy$getProperty:(NSString *)name { if ([name isEqualToString:@"length"]) return [NSNumber numberWithUnsignedInteger:[self count]]; @@ -837,6 +873,10 @@ NSString *NSCFType$cy$toJSON(id self, SEL sel, NSString *key) { return json; } +- (bool) cy$hasProperty:(NSString *)name { + return [self objectForKey:name] != nil; +} + - (NSObject *) cy$getProperty:(NSString *)name { return [self objectForKey:name]; } @@ -1362,39 +1402,44 @@ bool CYIsCallable(JSContextRef context, JSValueRef value) { @end NSString *CYCopyNSCYON(id value) { - Class _class(object_getClass(value)); - SEL sel(@selector(cy$toCYON)); - NSString *string; - if (Method toCYON = class_getInstanceMethod(_class, sel)) - string = reinterpret_cast<NSString *(*)(id, SEL)>(method_getImplementation(toCYON))(value, sel); - else if (Method methodSignatureForSelector = class_getInstanceMethod(_class, @selector(methodSignatureForSelector:))) { - if (reinterpret_cast<NSMethodSignature *(*)(id, SEL, SEL)>(method_getImplementation(methodSignatureForSelector))(value, @selector(methodSignatureForSelector:), sel) != nil) - string = [value cy$toCYON]; - else goto fail; - } else fail: { - if (value == NSZombie_) - string = @"_NSZombie_"; - else if (_class == NSZombie_) - string = [NSString stringWithFormat:@"<_NSZombie_: %p>", value]; - // XXX: frowny /in/ the pants - else if (value == NSMessageBuilder_ || value == Object_) - string = nil; - else - string = [NSString stringWithFormat:@"%@", value]; + if (value == nil) + string = @"nil"; + else { + Class _class(object_getClass(value)); + SEL sel(@selector(cy$toCYON)); + + if (Method toCYON = class_getInstanceMethod(_class, sel)) + string = reinterpret_cast<NSString *(*)(id, SEL)>(method_getImplementation(toCYON))(value, sel); + else if (Method methodSignatureForSelector = class_getInstanceMethod(_class, @selector(methodSignatureForSelector:))) { + if (reinterpret_cast<NSMethodSignature *(*)(id, SEL, SEL)>(method_getImplementation(methodSignatureForSelector))(value, @selector(methodSignatureForSelector:), sel) != nil) + string = [value cy$toCYON]; + else goto fail; + } else fail: { + if (value == NSZombie_) + string = @"_NSZombie_"; + else if (_class == NSZombie_) + string = [NSString stringWithFormat:@"<_NSZombie_: %p>", value]; + // XXX: frowny /in/ the pants + else if (value == NSMessageBuilder_ || value == Object_) + string = nil; + else + string = [NSString stringWithFormat:@"%@", value]; + } + + // XXX: frowny pants + if (string == nil) + string = @"undefined"; } - // XXX: frowny pants - if (string == nil) - string = @"undefined"; return [string retain]; } NSString *CYCopyNSCYON(JSContextRef context, JSValueRef value, JSValueRef *exception) { CYTry { CYPoolTry { - return CYCopyNSCYON(CYCastNSObject(NULL, context, value) ?: [NSNull null]); + return CYCopyNSCYON(CYCastNSObject(NULL, context, value)); } CYPoolCatch(NULL) } CYCatch } @@ -1449,6 +1494,12 @@ struct CYInternal : return internal; } + bool HasProperty(JSContextRef context, JSStringRef name) { + if (object_ == NULL) + return false; + return JSObjectHasProperty(context, object_, name); + } + JSValueRef GetProperty(JSContextRef context, JSStringRef name) { if (object_ == NULL) return NULL; @@ -1698,11 +1749,52 @@ JSValueRef CYFromFFI(JSContextRef context, sig::Type *type, ffi_type *ffi, void return value; } -static JSValueRef Instance_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { +static bool CYImplements(id object, Class _class, SEL selector) { + // XXX: possibly use a more "awesome" check? + return class_getInstanceMethod(_class, selector) != NULL; +} + +static bool Instance_hasProperty(JSContextRef context, JSObjectRef object, JSStringRef property) { + Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(object))); + id self(internal->GetValue()); + + if (JSStringIsEqualToUTF8CString(property, "$cyi")) + return true; + CYPool pool; + NSString *name(CYCastNSString(pool, property)); + + if (CYInternal *internal = CYInternal::Get(self)) + if (internal->HasProperty(context, property)) + return true; + + CYPoolTry { + if ([self cy$hasProperty:name]) + return true; + } CYPoolCatch(false) + + const char *string(CYPoolCString(pool, name)); + Class _class(object_getClass(self)); + + if (class_getProperty(_class, string) != NULL) + return true; + + if (SEL sel = sel_getUid(string)) + if (CYImplements(self, _class, sel)) + return true; + + return false; +} + +static JSValueRef Instance_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { + Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(object))); + id self(internal->GetValue()); + + if (JSStringIsEqualToUTF8CString(property, "$cyi")) + return Internal::Make(context, self, object); CYTry { - id self(CYCastNSObject(pool, context, object)); + CYPool pool; NSString *name(CYCastNSString(pool, property)); if (CYInternal *internal = CYInternal::Get(self)) @@ -1724,19 +1816,13 @@ static JSValueRef Instance_getProperty(JSContextRef context, JSObjectRef object, } if (SEL sel = sel_getUid(string)) - // XXX: possibly use a more "awesome" check? - if (class_getInstanceMethod(_class, sel) != NULL) + if (CYImplements(self, _class, sel)) return CYSendMessage(pool, context, self, sel, 0, NULL, false, exception); return NULL; } CYCatch } -static JSValueRef Instance_getProperty_$cyi(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { - Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(object))); - return Internal::Make(context, internal->GetValue(), object); -} - static bool Instance_setProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef value, JSValueRef *exception) { CYPool pool; @@ -1780,8 +1866,7 @@ static bool Instance_setProperty(JSContextRef context, JSObjectRef object, JSStr set[length + 4] = '\0'; if (SEL sel = sel_getUid(set)) - // XXX: possibly use a more "awesome" check? - if (class_getInstanceMethod(_class, sel) != NULL) { + if (CYImplements(self, _class, sel)) { JSValueRef arguments[1] = {value}; CYSendMessage(pool, context, self, sel, 1, arguments, false, exception); } @@ -1827,6 +1912,19 @@ static JSObjectRef Instance_callAsConstructor(JSContextRef context, JSObjectRef } CYCatch } +static bool Internal_hasProperty(JSContextRef context, JSObjectRef object, JSStringRef property) { + Internal *internal(reinterpret_cast<Internal *>(JSObjectGetPrivate(object))); + CYPool pool; + + id self(internal->GetValue()); + const char *name(CYPoolCString(pool, property)); + + if (object_getInstanceVariable(self, name, NULL) != NULL) + return true; + + return false; +} + static JSValueRef Internal_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { Internal *internal(reinterpret_cast<Internal *>(JSObjectGetPrivate(object))); CYPool pool; @@ -2237,6 +2335,9 @@ static void ObjectiveC_Protocols_getPropertyNames(JSContextRef context, JSObject } static JSValueRef Runtime_getProperty(JSContextRef context, JSObjectRef object, JSStringRef property, JSValueRef *exception) { + if (JSStringIsEqualToUTF8CString(property, "nil")) + return Instance::Make(context, nil, Instance::None); + CYTry { CYPool pool; NSString *name(CYCastNSString(pool, property)); @@ -2453,6 +2554,15 @@ static JSObjectRef Type_callAsConstructor(JSContextRef context, JSObjectRef obje } CYCatch } +JSObjectRef Instance_new(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { + CYTry { + if (count > 1) + @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"incorrect number of arguments to Instance constructor" userInfo:nil]; + id self(count == 0 ? nil : CYCastPointer<id>(context, arguments[0])); + return Instance::Make(context, self, Instance::None); + } CYCatch +} + JSObjectRef Functor_new(JSContextRef context, JSObjectRef object, size_t count, const JSValueRef arguments[], JSValueRef *exception) { CYTry { if (count != 2) @@ -2480,9 +2590,28 @@ JSValueRef Selector_getProperty_prototype(JSContextRef context, JSObjectRef obje return Function_; } +static JSValueRef CYValue_callAsFunction_$cya(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { + CYValue *internal(reinterpret_cast<CYValue *>(JSObjectGetPrivate(_this))); + Type_privateData *typical(internal->GetType()); + + sig::Type *type; + ffi_type *ffi; + + if (typical == NULL) { + type = NULL; + ffi = NULL; + } else { + type = typical->type_; + ffi = typical->ffi_; + } + + return CYMakePointer(context, &internal->value_, type, ffi, object); +} + static JSValueRef CYValue_callAsFunction_valueOf(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { + CYValue *internal(reinterpret_cast<CYValue *>(JSObjectGetPrivate(_this))); + CYTry { - CYValue *internal(reinterpret_cast<CYValue *>(JSObjectGetPrivate(_this))); return CYCastJSValue(context, reinterpret_cast<uintptr_t>(internal->value_)); } CYCatch } @@ -2492,26 +2621,29 @@ static JSValueRef CYValue_callAsFunction_toJSON(JSContextRef context, JSObjectRe } static JSValueRef CYValue_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { + CYValue *internal(reinterpret_cast<CYValue *>(JSObjectGetPrivate(_this))); + char string[32]; + sprintf(string, "%p", internal->value_); + CYTry { - CYValue *internal(reinterpret_cast<CYValue *>(JSObjectGetPrivate(_this))); - char string[32]; - sprintf(string, "%p", internal->value_); return CYCastJSValue(context, string); } CYCatch } static JSValueRef Instance_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { + Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(_this))); + CYTry { - Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(_this))); CYPoolTry { - return CYCastJSValue(context, CYJSString([internal->GetValue() cy$toCYON])); + return CYCastJSValue(context, CYJSString(CYPoolNSCYON(NULL, internal->GetValue()))); } CYPoolCatch(NULL) } CYCatch } static JSValueRef Instance_callAsFunction_toJSON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { + Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(_this))); + CYTry { - Instance *internal(reinterpret_cast<Instance *>(JSObjectGetPrivate(_this))); CYPoolTry { NSString *key(count == 0 ? nil : CYCastNSString(NULL, CYJSString(context, arguments[0]))); return CYCastJSValue(context, CYJSString([internal->GetValue() cy$toJSON:key])); @@ -2520,8 +2652,9 @@ static JSValueRef Instance_callAsFunction_toJSON(JSContextRef context, JSObjectR } static JSValueRef Instance_callAsFunction_toString(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { + Instance *data(reinterpret_cast<Instance *>(JSObjectGetPrivate(_this))); + CYTry { - Instance *data(reinterpret_cast<Instance *>(JSObjectGetPrivate(_this))); CYPoolTry { return CYCastJSValue(context, CYJSString([data->GetValue() description])); } CYPoolCatch(NULL) @@ -2529,8 +2662,9 @@ static JSValueRef Instance_callAsFunction_toString(JSContextRef context, JSObjec } static JSValueRef Selector_callAsFunction_toString(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { + Selector_privateData *data(reinterpret_cast<Selector_privateData *>(JSObjectGetPrivate(_this))); + CYTry { - Selector_privateData *data(reinterpret_cast<Selector_privateData *>(JSObjectGetPrivate(_this))); return CYCastJSValue(context, sel_getName(data->GetValue())); } CYCatch } @@ -2540,9 +2674,10 @@ static JSValueRef Selector_callAsFunction_toJSON(JSContextRef context, JSObjectR } static JSValueRef Selector_callAsFunction_toCYON(JSContextRef context, JSObjectRef object, JSObjectRef _this, size_t count, const JSValueRef arguments[], JSValueRef *exception) { + Selector_privateData *internal(reinterpret_cast<Selector_privateData *>(JSObjectGetPrivate(_this))); + const char *name(sel_getName(internal->GetValue())); + CYTry { - Selector_privateData *internal(reinterpret_cast<Selector_privateData *>(JSObjectGetPrivate(_this))); - const char *name(sel_getName(internal->GetValue())); CYPoolTry { return CYCastJSValue(context, CYJSString([NSString stringWithFormat:@"@selector(%s)", name])); } CYPoolCatch(NULL) @@ -2598,7 +2733,7 @@ static JSStaticValue CYValue_staticValues[2] = { }; static JSStaticValue Pointer_staticValues[2] = { - {"$cyi", &Pointer_getProperty_$cyi, &Pointer_setProperty_$cyi, kJSPropertyAttributeDontDelete}, + {"$cyi", &Pointer_getProperty_$cyi, &Pointer_setProperty_$cyi, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, {NULL, NULL, NULL, 0} }; @@ -2626,13 +2761,13 @@ static JSStaticFunction Functor_staticFunctions[4] = { {NULL, NULL, NULL, 0} };*/ -static JSStaticValue Instance_staticValues[3] = { +static JSStaticValue Instance_staticValues[2] = { {"value", &CYValue_getProperty_value, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete}, - {"$cyi", &Instance_getProperty_$cyi, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete}, {NULL, NULL, NULL, 0} }; -static JSStaticFunction Instance_staticFunctions[4] = { +static JSStaticFunction Instance_staticFunctions[5] = { + {"$cya", &CYValue_callAsFunction_$cya, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, {"toCYON", &Instance_callAsFunction_toCYON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, {"toJSON", &Instance_callAsFunction_toJSON, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, {"toString", &Instance_callAsFunction_toString, kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete}, @@ -2854,6 +2989,9 @@ MSInitialize { _pooled _aprcall(apr_initialize()); _aprcall(apr_pool_create(&Pool_, NULL)); + Type_privateData::Object = new(Pool_) Type_privateData(Pool_, "@"); + Type_privateData::Selector = new(Pool_) Type_privateData(Pool_, ":"); + Bridge_ = [[NSMutableArray arrayWithContentsOfFile:@"/usr/lib/libcycript.plist"] retain]; NSCFBoolean_ = objc_getClass("NSCFBoolean"); @@ -2901,6 +3039,7 @@ JSGlobalContextRef CYGetJSContext() { definition.className = "Instance"; definition.staticValues = Instance_staticValues; definition.staticFunctions = Instance_staticFunctions; + definition.hasProperty = &Instance_hasProperty; definition.getProperty = &Instance_getProperty; definition.setProperty = &Instance_setProperty; definition.deleteProperty = &Instance_deleteProperty; @@ -2912,6 +3051,7 @@ JSGlobalContextRef CYGetJSContext() { definition = kJSClassDefinitionEmpty; definition.className = "Internal"; definition.staticFunctions = Internal_staticFunctions; + definition.hasProperty = &Internal_hasProperty; definition.getProperty = &Internal_getProperty; definition.setProperty = &Internal_setProperty; definition.getPropertyNames = &Internal_getPropertyNames; @@ -3002,7 +3142,7 @@ JSGlobalContextRef CYGetJSContext() { CYSetProperty(context, ObjectiveC_, CYJSString("protocols"), JSObjectMake(context, ObjectiveC_Protocols_, NULL)); CYSetProperty(context, global, CYJSString("Functor"), JSObjectMakeConstructor(context, Functor_, &Functor_new)); - CYSetProperty(context, global, CYJSString("Instance"), JSObjectMakeConstructor(context, Instance_, NULL)); + CYSetProperty(context, global, CYJSString("Instance"), JSObjectMakeConstructor(context, Instance_, &Instance_new)); CYSetProperty(context, global, CYJSString("Pointer"), JSObjectMakeConstructor(context, Pointer_, &Pointer_new)); CYSetProperty(context, global, CYJSString("Selector"), JSObjectMakeConstructor(context, Selector_, &Selector_new)); CYSetProperty(context, global, CYJSString("Type"), JSObjectMakeConstructor(context, Type_, &Type_new)); -- 2.47.2